Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[serve] Enable REST API tests with main clause #22706

Merged
merged 14 commits into from
Mar 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions dashboard/modules/serve/tests/test_schema.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import sys

from pydantic import ValidationError

import pytest

import requests
Expand Down Expand Up @@ -586,3 +589,7 @@ def f2():
assert len(deployment_names) == 0

serve.shutdown()


if __name__ == "__main__":
sys.exit(pytest.main(["-v", __file__]))
117 changes: 83 additions & 34 deletions dashboard/modules/serve/tests/test_serve_head.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import pytest
import json
import subprocess
import sys
import os
from typing import List, Dict, Set

import pytest

import requests
import json
from typing import List, Dict


GET_OR_PUT_URL = "http://localhost:8265/api/serve/deployments/"
Expand All @@ -12,15 +16,17 @@


@pytest.fixture
def serve_start_stop():
def ray_start_stop():
subprocess.check_output(["ray", "start", "--head"])
subprocess.check_output(["serve", "start"])
yield
subprocess.check_output(["ray", "stop", "--force"])


def deployments_match(list1: List[Dict], list2: List[Dict]) -> bool:
# Helper that takes in 2 lists of deployment dictionaries and compares them
def deployments_match(list1: List[Dict], list2: List[Dict], properties: Set) -> bool:
"""
Helper that takes in 2 lists of deployment dictionaries and compares their
properties and ray_actor_options.
"""

if len(list1) != len(list2):
return False
Expand All @@ -29,7 +35,10 @@ def deployments_match(list1: List[Dict], list2: List[Dict]) -> bool:
matching_deployment = None
for i in range(len(list2)):
deployment2 = list2[i]
if deployment1 == deployment2:
for property in properties:
if deployment1[property] != deployment2[property]:
break
else:
matching_deployment = i
if matching_deployment is None:
return False
Expand All @@ -38,8 +47,14 @@ def deployments_match(list1: List[Dict], list2: List[Dict]) -> bool:
return len(list2) == 0


def test_put_get_success(serve_start_stop):
ray_actor_options = {"runtime_env": {"py_modules": [test_env_uri, test_module_uri]}}
@pytest.mark.skipif(
sys.platform == "win32", reason="File paths incompatible with Windows."
)
def test_put_get_success(ray_start_stop):
ray_actor_options = {
"runtime_env": {"py_modules": [test_env_uri, test_module_uri]},
"num_cpus": 0.1,
}

shallow = dict(
name="shallow",
Expand All @@ -64,45 +79,70 @@ def test_put_get_success(serve_start_stop):
import_path="test_module.test.one",
)

three_deployments = os.path.join(
os.path.dirname(__file__), "three_deployments_response.json"
)

two_deployments = os.path.join(
os.path.dirname(__file__), "two_deployments_response.json"
)

# Ensure the REST API is idempotent
for _ in range(3):
for _ in range(2):
deployments = [shallow, deep, one]

put_response = requests.put(GET_OR_PUT_URL, json={"deployments": deployments})
put_response = requests.put(
GET_OR_PUT_URL, json={"deployments": deployments}, timeout=30
)
assert put_response.status_code == 200
assert (
requests.get("http://localhost:8000/shallow").text == "Hello shallow world!"
requests.get("http://localhost:8000/shallow", timeout=30).text
== "Hello shallow world!"
)
assert (
requests.get("http://localhost:8000/deep", timeout=30).text
== "Hello deep world!"
)
assert requests.get("http://localhost:8000/deep").text == "Hello deep world!"
assert requests.get("http://localhost:8000/one").text == "2"
assert requests.get("http://localhost:8000/one", timeout=30).text == "2"

get_response = requests.get(GET_OR_PUT_URL)
get_response = requests.get(GET_OR_PUT_URL, timeout=30)
assert get_response.status_code == 200

with open("three_deployments_response.json", "r") as f:
with open(three_deployments, "r") as f:
response_deployments = get_response.json()["deployments"]
expected_deployments = json.load(f)["deployments"]
assert deployments_match(response_deployments, expected_deployments)
assert deployments_match(
response_deployments,
expected_deployments,
{"name", "import_path", "num_replicas", "route_prefix"},
)

deployments = [shallow, one]
put_response = requests.put(GET_OR_PUT_URL, json={"deployments": deployments})
put_response = requests.put(
GET_OR_PUT_URL, json={"deployments": deployments}, timeout=30
)
assert put_response.status_code == 200
assert (
requests.get("http://localhost:8000/shallow").text == "Hello shallow world!"
requests.get("http://localhost:8000/shallow", timeout=30).text
== "Hello shallow world!"
)
assert requests.get("http://localhost:8000/deep").status_code == 404
assert requests.get("http://localhost:8000/one").text == "2"
assert requests.get("http://localhost:8000/deep", timeout=30).status_code == 404
assert requests.get("http://localhost:8000/one", timeout=30).text == "2"

get_response = requests.get(GET_OR_PUT_URL)
get_response = requests.get(GET_OR_PUT_URL, timeout=30)
assert get_response.status_code == 200

with open("two_deployments_response.json", "r") as f:
with open(two_deployments, "r") as f:
response_deployments = get_response.json()["deployments"]
expected_deployments = json.load(f)["deployments"]
assert deployments_match(response_deployments, expected_deployments)
assert deployments_match(
response_deployments,
expected_deployments,
{"name", "import_path", "num_replicas", "route_prefix"},
)


def test_delete_success(serve_start_stop):
def test_delete_success(ray_start_stop):
ray_actor_options = {
"runtime_env": {
"working_dir": (
Expand All @@ -121,22 +161,25 @@ def test_delete_success(serve_start_stop):
)

# Ensure the REST API is idempotent
for _ in range(5):
put_response = requests.put(GET_OR_PUT_URL, json={"deployments": [shallow]})
for _ in range(2):
put_response = requests.put(
GET_OR_PUT_URL, json={"deployments": [shallow]}, timeout=30
)
assert put_response.status_code == 200
assert (
requests.get("http://localhost:8000/shallow").text == "Hello shallow world!"
requests.get("http://localhost:8000/shallow", timeout=30).text
== "Hello shallow world!"
)

delete_response = requests.delete(GET_OR_PUT_URL)
delete_response = requests.delete(GET_OR_PUT_URL, timeout=30)
assert delete_response.status_code == 200

# Make sure no deployments exist
get_response = requests.get(GET_OR_PUT_URL)
get_response = requests.get(GET_OR_PUT_URL, timeout=30)
assert len(get_response.json()["deployments"]) == 0


def test_get_status_info(serve_start_stop):
def test_get_status_info(ray_start_stop):
ray_actor_options = {"runtime_env": {"py_modules": [test_env_uri, test_module_uri]}}

shallow = dict(
Expand Down Expand Up @@ -164,10 +207,12 @@ def test_get_status_info(serve_start_stop):

deployments = [shallow, deep, one]

put_response = requests.put(GET_OR_PUT_URL, json={"deployments": deployments})
put_response = requests.put(
GET_OR_PUT_URL, json={"deployments": deployments}, timeout=30
)
assert put_response.status_code == 200

status_response = requests.get(STATUS_URL)
status_response = requests.get(STATUS_URL, timeout=30)
assert status_response.status_code == 200

statuses = status_response.json()["statuses"]
Expand All @@ -181,3 +226,7 @@ def test_get_status_info(serve_start_stop):
assert len(expected_deployment_names) == 0

print(statuses)


if __name__ == "__main__":
sys.exit(pytest.main(["-v", __file__]))
6 changes: 3 additions & 3 deletions dashboard/modules/serve/tests/three_deployments_response.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
],
"working_dir": null
},
"num_cpus": 1.0,
"num_cpus": 0.1,
"num_gpus": 0.0,
"memory": 0.0,
"object_store_memory": 0.0,
Expand Down Expand Up @@ -54,7 +54,7 @@
],
"working_dir": null
},
"num_cpus": 1.0,
"num_cpus": 0.1,
"num_gpus": 0.0,
"memory": 0.0,
"object_store_memory": 0.0,
Expand Down Expand Up @@ -85,7 +85,7 @@
],
"working_dir": null
},
"num_cpus": 1.0,
"num_cpus": 0.1,
"num_gpus": 0.0,
"memory": 0.0,
"object_store_memory": 0.0,
Expand Down
4 changes: 2 additions & 2 deletions dashboard/modules/serve/tests/two_deployments_response.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
],
"working_dir": null
},
"num_cpus": 1.0,
"num_cpus": 0.1,
"num_gpus": 0.0,
"memory": 0.0,
"object_store_memory": 0.0,
Expand Down Expand Up @@ -54,7 +54,7 @@
],
"working_dir": null
},
"num_cpus": 1.0,
"num_cpus": 0.1,
"num_gpus": 0.0,
"memory": 0.0,
"object_store_memory": 0.0,
Expand Down