ray/dashboard/modules/job/tests/test_common.py
Alan Guo 5d6bc5360d
Fix the jobs tab in the beta dashboard and fill it with data from both "submission" jobs and "driver" jobs (#25902)
## Why are these changes needed?
- Fixes the jobs tab in the new dashboard. Previously it didn't load.
- Combines the old job concept, "driver jobs" and the new job submission conception into a single concept called "jobs". Jobs tab shows information about both jobs.

- Updates all job APIs: They now returns both submission jobs and driver jobs. They also contains additional data in the response including "id", "job_id", "submission_id", and "driver". They also accept either job_id or submission_id as input.

- Job ID is the same as the "ray core job id" concept. It is in the form of "0100000" and is the primary id to represent jobs.
- Submission ID is an ID that is generated for each ray job submission. It is in the form of "raysubmit_12345...". It is a secondary id that can be used if a client needs to provide a self-generated id. or if the job id doesn't exist (ex: if the submission job doesn't create a ray driver)

This PR has 2 deprecations
- The `submit_job` sdk now accepts a new kwarg `submission_id`. `job_id is deprecated.
- The `ray job submit` CLI now accepts `--submission-id`. `--job-id` is deprecated.

**This PR has 4 backwards incompatible changes:**
- list_jobs sdk now returns a list instead of a dictionary
- the `ray job list` CLI now prints a list instead of a dictionary
- The `/api/jobs` endpoint returns a list instead of a dictionary
- The `POST api/jobs` endpoint (submit job) now returns a json with `submission_id` field instead of `job_id`.
2022-07-27 02:39:52 -07:00

111 lines
4 KiB
Python

import pytest
from ray.dashboard.modules.job.common import (
http_uri_components_to_uri,
uri_to_http_components,
validate_request_type,
JobSubmitRequest,
)
class TestJobSubmitRequestValidation:
def test_validate_entrypoint(self):
r = validate_request_type({"entrypoint": "abc"}, JobSubmitRequest)
assert r.entrypoint == "abc"
with pytest.raises(TypeError, match="required positional argument"):
validate_request_type({}, JobSubmitRequest)
with pytest.raises(TypeError, match="must be a string"):
validate_request_type({"entrypoint": 123}, JobSubmitRequest)
def test_validate_submission_id(self):
r = validate_request_type({"entrypoint": "abc"}, JobSubmitRequest)
assert r.entrypoint == "abc"
assert r.submission_id is None
r = validate_request_type(
{"entrypoint": "abc", "submission_id": "123"}, JobSubmitRequest
)
assert r.entrypoint == "abc"
assert r.submission_id == "123"
with pytest.raises(TypeError, match="must be a string"):
validate_request_type(
{"entrypoint": 123, "submission_id": 1}, JobSubmitRequest
)
def test_validate_runtime_env(self):
r = validate_request_type({"entrypoint": "abc"}, JobSubmitRequest)
assert r.entrypoint == "abc"
assert r.runtime_env is None
r = validate_request_type(
{"entrypoint": "abc", "runtime_env": {"hi": "hi2"}}, JobSubmitRequest
)
assert r.entrypoint == "abc"
assert r.runtime_env == {"hi": "hi2"}
with pytest.raises(TypeError, match="must be a dict"):
validate_request_type(
{"entrypoint": "abc", "runtime_env": 123}, JobSubmitRequest
)
with pytest.raises(TypeError, match="keys must be strings"):
validate_request_type(
{"entrypoint": "abc", "runtime_env": {1: "hi"}}, JobSubmitRequest
)
def test_validate_metadata(self):
r = validate_request_type({"entrypoint": "abc"}, JobSubmitRequest)
assert r.entrypoint == "abc"
assert r.metadata is None
r = validate_request_type(
{"entrypoint": "abc", "metadata": {"hi": "hi2"}}, JobSubmitRequest
)
assert r.entrypoint == "abc"
assert r.metadata == {"hi": "hi2"}
with pytest.raises(TypeError, match="must be a dict"):
validate_request_type(
{"entrypoint": "abc", "metadata": 123}, JobSubmitRequest
)
with pytest.raises(TypeError, match="keys must be strings"):
validate_request_type(
{"entrypoint": "abc", "metadata": {1: "hi"}}, JobSubmitRequest
)
with pytest.raises(TypeError, match="values must be strings"):
validate_request_type(
{"entrypoint": "abc", "metadata": {"hi": 1}}, JobSubmitRequest
)
def test_uri_to_http_and_back():
assert uri_to_http_components("gcs://hello.zip") == ("gcs", "hello.zip")
assert uri_to_http_components("gcs://hello.whl") == ("gcs", "hello.whl")
with pytest.raises(ValueError, match="'blah' is not a valid Protocol"):
uri_to_http_components("blah://halb.zip")
with pytest.raises(ValueError, match="does not end in .zip or .whl"):
assert uri_to_http_components("gcs://hello.not_zip")
with pytest.raises(ValueError, match="does not end in .zip or .whl"):
assert uri_to_http_components("gcs://hello")
assert http_uri_components_to_uri("gcs", "hello.zip") == "gcs://hello.zip"
assert http_uri_components_to_uri("blah", "halb.zip") == "blah://halb.zip"
assert http_uri_components_to_uri("blah", "halb.whl") == "blah://halb.whl"
for original_uri in ["gcs://hello.zip", "gcs://fasdf.whl"]:
new_uri = http_uri_components_to_uri(*uri_to_http_components(original_uri))
assert new_uri == original_uri
if __name__ == "__main__":
import sys
sys.exit(pytest.main(["-v", __file__]))