chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import logging
|
||||
|
||||
import aiohttp.web
|
||||
|
||||
import ray.dashboard.modules.tests.test_consts as test_consts
|
||||
import ray.dashboard.modules.tests.test_utils as test_utils
|
||||
import ray.dashboard.optional_utils as dashboard_optional_utils
|
||||
import ray.dashboard.utils as dashboard_utils
|
||||
from ray._private.ray_constants import env_bool
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
routes = dashboard_optional_utils.DashboardAgentRouteTable
|
||||
|
||||
|
||||
@dashboard_utils.dashboard_module(
|
||||
enable=env_bool(test_consts.TEST_MODULE_ENVIRONMENT_KEY, False)
|
||||
)
|
||||
class TestAgent(dashboard_utils.DashboardAgentModule):
|
||||
def __init__(self, dashboard_agent):
|
||||
super().__init__(dashboard_agent)
|
||||
|
||||
@staticmethod
|
||||
def is_minimal_module():
|
||||
return False
|
||||
|
||||
@routes.get("/test/http_get_from_agent")
|
||||
async def get_url(self, req) -> aiohttp.web.Response:
|
||||
url = req.query.get("url")
|
||||
result = await test_utils.http_get(self._dashboard_agent.http_session, url)
|
||||
return aiohttp.web.json_response(result)
|
||||
|
||||
@routes.head("/test/route_head")
|
||||
async def route_head(self, req) -> aiohttp.web.Response:
|
||||
pass
|
||||
|
||||
@routes.post("/test/route_post")
|
||||
async def route_post(self, req) -> aiohttp.web.Response:
|
||||
pass
|
||||
|
||||
@routes.patch("/test/route_patch")
|
||||
async def route_patch(self, req) -> aiohttp.web.Response:
|
||||
pass
|
||||
|
||||
async def run(self, server):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
@@ -0,0 +1,5 @@
|
||||
py_modules:
|
||||
- "pm1"
|
||||
- "pm2"
|
||||
|
||||
working_dir: "wd"
|
||||
@@ -0,0 +1,4 @@
|
||||
TEST_MODULE_ENVIRONMENT_KEY = "RAY_DASHBOARD_MODULE_TEST"
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
@@ -0,0 +1,103 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from ray.dashboard.modules.dashboard_sdk import (
|
||||
parse_cluster_info,
|
||||
parse_runtime_env_args,
|
||||
)
|
||||
|
||||
|
||||
class TestParseRuntimeEnvArgs:
|
||||
@pytest.mark.skipif(
|
||||
sys.platform == "win32", reason="File path incorrect on Windows."
|
||||
)
|
||||
def test_runtime_env_valid(self):
|
||||
config_file_name = os.path.join(
|
||||
os.path.dirname(__file__), "test_config_files", "basic_runtime_env.yaml"
|
||||
)
|
||||
assert parse_runtime_env_args(runtime_env=config_file_name) == {
|
||||
"py_modules": ["pm1", "pm2"],
|
||||
"working_dir": "wd",
|
||||
}
|
||||
|
||||
def test_runtime_env_json_valid(self):
|
||||
runtime_env = '{"py_modules": ["pm1", "pm2"], "working_dir": "wd"}'
|
||||
assert parse_runtime_env_args(runtime_env_json=runtime_env) == {
|
||||
"py_modules": ["pm1", "pm2"],
|
||||
"working_dir": "wd",
|
||||
}
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.platform == "win32", reason="File path incorrect on Windows."
|
||||
)
|
||||
def test_runtime_env_and_json(self):
|
||||
config_file_name = os.path.join(
|
||||
os.path.dirname(__file__), "test_config_files", "basic_runtime_env.yaml"
|
||||
)
|
||||
runtime_env_json = '{"py_modules": ["pm1", "pm2"], "working_dir": "wd"}'
|
||||
with pytest.raises(ValueError):
|
||||
parse_runtime_env_args(
|
||||
runtime_env=config_file_name, runtime_env_json=runtime_env_json
|
||||
)
|
||||
|
||||
def test_working_dir_valid(self):
|
||||
assert parse_runtime_env_args(working_dir="wd") == {"working_dir": "wd"}
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.platform == "win32", reason="File path incorrect on Windows."
|
||||
)
|
||||
def test_working_dir_override(self):
|
||||
config_file_name = os.path.join(
|
||||
os.path.dirname(__file__), "test_config_files", "basic_runtime_env.yaml"
|
||||
)
|
||||
assert parse_runtime_env_args(
|
||||
runtime_env=config_file_name, working_dir="wd2"
|
||||
) == {"py_modules": ["pm1", "pm2"], "working_dir": "wd2"}
|
||||
|
||||
runtime_env = '{"py_modules": ["pm1", "pm2"], "working_dir": "wd2"}'
|
||||
assert parse_runtime_env_args(
|
||||
runtime_env_json=runtime_env, working_dir="wd2"
|
||||
) == {"py_modules": ["pm1", "pm2"], "working_dir": "wd2"}
|
||||
|
||||
def test_all_none(self):
|
||||
assert parse_runtime_env_args() == {}
|
||||
|
||||
|
||||
def test_get_job_submission_client_cluster_info():
|
||||
# Test that the name for get_job_submission_client_cluster_info stays the
|
||||
# same
|
||||
|
||||
from ray.dashboard.modules.dashboard_sdk import ( # noqa: F401
|
||||
get_job_submission_client_cluster_info,
|
||||
)
|
||||
|
||||
|
||||
def test_parse_cluster_address_validation():
|
||||
"""Test that parse_cluster_info validates address schemes."""
|
||||
|
||||
# Check that "auto" is rejected
|
||||
with pytest.raises(ValueError):
|
||||
parse_cluster_info("auto")
|
||||
|
||||
# Check that invalid schemes raise a ValueError
|
||||
invalid_schemes = ["ray"]
|
||||
for scheme in invalid_schemes:
|
||||
with pytest.raises(ValueError):
|
||||
parse_cluster_info(f"{scheme}://localhost:10001")
|
||||
|
||||
# Check that valid schemes are OK
|
||||
valid_schemes = ["http", "https"]
|
||||
for scheme in valid_schemes:
|
||||
parse_cluster_info(f"{scheme}://localhost:10001")
|
||||
|
||||
|
||||
def test_parse_cluster_info_ignores_extra_kwargs():
|
||||
"""Test that parse_cluster_info with http:// gracefully ignores extra kwargs."""
|
||||
result = parse_cluster_info("http://localhost:8265", cloud="test")
|
||||
assert result.address == "http://localhost:8265"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(pytest.main(["-v", __file__]))
|
||||
@@ -0,0 +1,97 @@
|
||||
import logging
|
||||
import time
|
||||
|
||||
import aiohttp.web
|
||||
|
||||
import ray.dashboard.modules.tests.test_consts as test_consts
|
||||
import ray.dashboard.modules.tests.test_utils as test_utils
|
||||
import ray.dashboard.optional_utils as dashboard_optional_utils
|
||||
import ray.dashboard.utils as dashboard_utils
|
||||
from ray._private.ray_constants import env_bool
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
routes = dashboard_optional_utils.DashboardHeadRouteTable
|
||||
|
||||
|
||||
@dashboard_utils.dashboard_module(
|
||||
enable=env_bool(test_consts.TEST_MODULE_ENVIRONMENT_KEY, False)
|
||||
)
|
||||
class TestHead(dashboard_utils.DashboardHeadModule):
|
||||
def __init__(self, config: dashboard_utils.DashboardHeadModuleConfig):
|
||||
super().__init__(config)
|
||||
|
||||
@staticmethod
|
||||
def is_minimal_module():
|
||||
return False
|
||||
|
||||
@routes.get("/test/route_get")
|
||||
async def route_get(self, req) -> aiohttp.web.Response:
|
||||
pass
|
||||
|
||||
@routes.put("/test/route_put")
|
||||
async def route_put(self, req) -> aiohttp.web.Response:
|
||||
pass
|
||||
|
||||
@routes.delete("/test/route_delete")
|
||||
async def route_delete(self, req) -> aiohttp.web.Response:
|
||||
pass
|
||||
|
||||
@routes.view("/test/route_view")
|
||||
async def route_view(self, req) -> aiohttp.web.Response:
|
||||
pass
|
||||
|
||||
@routes.get("/test/http_get")
|
||||
async def get_url(self, req) -> aiohttp.web.Response:
|
||||
url = req.query.get("url")
|
||||
result = await test_utils.http_get(self.http_session, url)
|
||||
return aiohttp.web.json_response(result)
|
||||
|
||||
@routes.get("/test/aiohttp_cache/{sub_path}")
|
||||
@dashboard_optional_utils.aiohttp_cache(ttl_seconds=1)
|
||||
async def test_aiohttp_cache(self, req) -> aiohttp.web.Response:
|
||||
value = req.query["value"]
|
||||
return dashboard_optional_utils.rest_response(
|
||||
status_code=dashboard_utils.HTTPStatusCode.OK,
|
||||
message="OK",
|
||||
value=value,
|
||||
timestamp=time.time(),
|
||||
)
|
||||
|
||||
@routes.get("/test/aiohttp_cache_lru/{sub_path}")
|
||||
@dashboard_optional_utils.aiohttp_cache(ttl_seconds=60, maxsize=5)
|
||||
async def test_aiohttp_cache_lru(self, req) -> aiohttp.web.Response:
|
||||
value = req.query.get("value")
|
||||
return dashboard_optional_utils.rest_response(
|
||||
status_code=dashboard_utils.HTTPStatusCode.OK,
|
||||
message="OK",
|
||||
value=value,
|
||||
timestamp=time.time(),
|
||||
)
|
||||
|
||||
@routes.get("/test/file")
|
||||
async def test_file(self, req) -> aiohttp.web.FileResponse:
|
||||
file_path = req.query.get("path")
|
||||
logger.info("test file: %s", file_path)
|
||||
return aiohttp.web.FileResponse(file_path)
|
||||
|
||||
@routes.get("/test/block_event_loop")
|
||||
async def block_event_loop(self, req) -> aiohttp.web.Response:
|
||||
"""
|
||||
Simulates a blocked event loop. To be used for testing purposes only. Creates a
|
||||
task that blocks the event loop for a specified number of seconds.
|
||||
"""
|
||||
seconds = float(req.query.get("seconds", 0.0))
|
||||
time.sleep(seconds)
|
||||
|
||||
return dashboard_optional_utils.rest_response(
|
||||
status_code=dashboard_utils.HTTPStatusCode.OK,
|
||||
message=f"Blocked event loop for {seconds} seconds",
|
||||
timestamp=time.time(),
|
||||
)
|
||||
|
||||
async def run(self):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
@@ -0,0 +1,70 @@
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from click.testing import CliRunner
|
||||
|
||||
from ray.dashboard.consts import PROMETHEUS_CONFIG_INPUT_PATH
|
||||
from ray.dashboard.modules.metrics import install_and_start_prometheus
|
||||
from ray.dashboard.modules.metrics.templates import PROMETHEUS_YML_TEMPLATE
|
||||
from ray.scripts.scripts import metrics_group
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"os_type,architecture",
|
||||
[
|
||||
("linux", "amd64"),
|
||||
("linux", "arm64"),
|
||||
("darwin", "amd64"),
|
||||
("darwin", "arm64"),
|
||||
("windows", "amd64"),
|
||||
("windows", "arm64"),
|
||||
],
|
||||
)
|
||||
def test_download_prometheus(os_type, architecture, monkeypatch):
|
||||
# set TEST_MODE_ENV_VAR to True to use requests.head instead of requests.get.
|
||||
# This will make the download faster. We just want to make sure the URL
|
||||
# exists.
|
||||
monkeypatch.setenv(install_and_start_prometheus.TEST_MODE_ENV_VAR, "True")
|
||||
downloaded, _ = install_and_start_prometheus.download_prometheus(
|
||||
os_type, architecture
|
||||
)
|
||||
assert downloaded
|
||||
|
||||
|
||||
def test_e2e(capsys):
|
||||
install_and_start_prometheus.main()
|
||||
captured = capsys.readouterr()
|
||||
assert "Prometheus is running" in captured.out
|
||||
# Find the Prometheus process and kill it.
|
||||
# Find the PID from the output: "To stop Prometheus, use the command: 'kill 22790'"
|
||||
pid = int(captured.out.split("kill ")[1].split("'")[0])
|
||||
subprocess.run(["kill", str(pid)])
|
||||
|
||||
|
||||
def test_shutdown_prometheus():
|
||||
install_and_start_prometheus.main()
|
||||
runner = CliRunner()
|
||||
# Sleep for a few seconds to make sure Prometheus is running
|
||||
# before we try to shut it down.
|
||||
time.sleep(5)
|
||||
result = runner.invoke(metrics_group, ["shutdown-prometheus"])
|
||||
assert result.exit_code == 0
|
||||
|
||||
|
||||
def test_prometheus_config_content():
|
||||
# Test to make sure the content in the hardcoded file
|
||||
# (python/ray/dashboard/modules/metrics/export/prometheus/prometheus.yml) will
|
||||
# always be the same as the template (templates.py) used to generate Prometheus
|
||||
# config file when Ray startup
|
||||
PROM_DISCOVERY_FILE_PATH = "/tmp/ray/prom_metrics_service_discovery.json"
|
||||
template_content = PROMETHEUS_YML_TEMPLATE.format(
|
||||
prom_metrics_service_discovery_file_path=PROM_DISCOVERY_FILE_PATH
|
||||
)
|
||||
with open(PROMETHEUS_CONFIG_INPUT_PATH) as f:
|
||||
assert f.read() == template_content
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(pytest.main(["-v", __file__]))
|
||||
@@ -0,0 +1,21 @@
|
||||
import logging
|
||||
import sys
|
||||
|
||||
# Import asyncio timeout depends on python version
|
||||
if sys.version_info >= (3, 11):
|
||||
from asyncio import timeout as asyncio_timeout
|
||||
else:
|
||||
from async_timeout import timeout as asyncio_timeout
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def http_get(http_session, url, timeout_seconds=60):
|
||||
async with asyncio_timeout(timeout_seconds):
|
||||
async with http_session.get(url) as response:
|
||||
return await response.json()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
Reference in New Issue
Block a user