Files
2026-07-13 13:22:34 +08:00

268 lines
9.5 KiB
Python

from unittest import mock
import pytest
from mlflow.deployments import get_deploy_client
from mlflow.deployments.mlflow import MlflowDeploymentClient
from mlflow.environment_variables import MLFLOW_DEPLOYMENT_CLIENT_HTTP_REQUEST_TIMEOUT
def test_get_deploy_client():
client = get_deploy_client("http://localhost:5000")
assert isinstance(client, MlflowDeploymentClient)
def test_create_endpoint():
client = get_deploy_client("http://localhost:5000")
with pytest.raises(NotImplementedError, match=r".*"):
client.create_endpoint(name="test")
def test_update_endpoint():
client = get_deploy_client("http://localhost:5000")
with pytest.raises(NotImplementedError, match=r".*"):
client.update_endpoint(endpoint="test")
def test_delete_endpoint():
client = get_deploy_client("http://localhost:5000")
with pytest.raises(NotImplementedError, match=r".*"):
client.delete_endpoint(endpoint="test")
def test_get_endpoint():
client = get_deploy_client("http://localhost:5000")
mock_resp = mock.Mock()
mock_resp.json.return_value = {
"model": {"name": "gpt-4", "provider": "openai"},
"name": "completions",
"endpoint_type": "llm/v1/completions",
"endpoint_url": "http://localhost:5000/endpoints/chat/invocations",
"limit": None,
}
mock_resp.status_code = 200
with mock.patch("requests.Session.request", return_value=mock_resp) as mock_request:
resp = client.get_endpoint(endpoint="test")
mock_request.assert_called_once()
assert resp.model_dump() == {
"name": "completions",
"endpoint_type": "llm/v1/completions",
"model": {"name": "gpt-4", "provider": "openai"},
"endpoint_url": "http://localhost:5000/endpoints/chat/invocations",
"limit": None,
}
((_, url), _) = mock_request.call_args
assert url == "http://localhost:5000/api/2.0/endpoints/test"
def test_list_endpoints():
client = get_deploy_client("http://localhost:5000")
mock_resp = mock.Mock()
mock_resp.json.return_value = {
"endpoints": [
{
"model": {"name": "gpt-4", "provider": "openai"},
"name": "completions",
"endpoint_type": "llm/v1/completions",
"endpoint_url": "http://localhost:5000/endpoints/chat/invocations",
"limit": None,
}
]
}
mock_resp.status_code = 200
with mock.patch("requests.Session.request", return_value=mock_resp) as mock_request:
resp = client.list_endpoints()
mock_request.assert_called_once()
assert [r.model_dump() for r in resp] == [
{
"model": {"name": "gpt-4", "provider": "openai"},
"name": "completions",
"endpoint_type": "llm/v1/completions",
"endpoint_url": "http://localhost:5000/endpoints/chat/invocations",
"limit": None,
}
]
((_, url), _) = mock_request.call_args
assert url == "http://localhost:5000/api/2.0/endpoints/"
def test_list_endpoints_paginated():
client = get_deploy_client("http://localhost:5000")
mock_resp = mock.Mock()
mock_resp.json.side_effect = [
{
"endpoints": [
{
"model": {"name": "gpt-4", "provider": "openai"},
"name": "chat",
"endpoint_type": "llm/v1/chat",
"endpoint_url": "http://localhost:5000/endpoints/chat/invocations",
"limit": None,
}
],
"next_page_token": "token",
},
{
"endpoints": [
{
"model": {"name": "gpt-4", "provider": "openai"},
"name": "completions",
"endpoint_type": "llm/v1/completions",
"endpoint_url": "http://localhost:5000/endpoints/chat/invocations",
"limit": None,
}
]
},
]
mock_resp.status_code = 200
with mock.patch("requests.Session.request", return_value=mock_resp) as mock_request:
resp = client.list_endpoints()
assert mock_request.call_count == 2
assert [r.model_dump() for r in resp] == [
{
"model": {"name": "gpt-4", "provider": "openai"},
"name": "chat",
"endpoint_type": "llm/v1/chat",
"endpoint_url": "http://localhost:5000/endpoints/chat/invocations",
"limit": None,
},
{
"model": {"name": "gpt-4", "provider": "openai"},
"name": "completions",
"endpoint_type": "llm/v1/completions",
"endpoint_url": "http://localhost:5000/endpoints/chat/invocations",
"limit": None,
},
]
def test_predict():
client = get_deploy_client("http://localhost:5000")
mock_resp = mock.Mock()
mock_resp.json.return_value = {
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"model": "gpt-4o-mini",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "hello",
},
"finish_reason": "stop",
}
],
"usage": {
"prompt_tokens": 9,
"completion_tokens": 12,
"total_tokens": 21,
},
}
mock_resp.status_code = 200
with mock.patch("requests.Session.request", return_value=mock_resp) as mock_request:
resp = client.predict(endpoint="test", inputs={})
mock_request.assert_called_once()
assert resp == {
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"model": "gpt-4o-mini",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "hello"},
"finish_reason": "stop",
}
],
"usage": {
"prompt_tokens": 9,
"completion_tokens": 12,
"total_tokens": 21,
},
}
((_, url), _) = mock_request.call_args
assert url == "http://localhost:5000/endpoints/test/invocations"
def test_call_endpoint_uses_default_timeout():
client = get_deploy_client("http://localhost:5000")
with mock.patch("mlflow.deployments.mlflow.http_request") as mock_http_request:
mock_http_request.return_value.json.return_value = {"test": "response"}
mock_http_request.return_value.status_code = 200
client._call_endpoint("GET", "/test")
mock_http_request.assert_called_once()
call_args = mock_http_request.call_args
assert call_args.kwargs["timeout"] == MLFLOW_DEPLOYMENT_CLIENT_HTTP_REQUEST_TIMEOUT.get()
def test_call_endpoint_respects_custom_timeout():
client = get_deploy_client("http://localhost:5000")
custom_timeout = 600
with mock.patch("mlflow.deployments.mlflow.http_request") as mock_http_request:
mock_http_request.return_value.json.return_value = {"test": "response"}
mock_http_request.return_value.status_code = 200
client._call_endpoint("GET", "/test", timeout=custom_timeout)
mock_http_request.assert_called_once()
call_args = mock_http_request.call_args
assert call_args.kwargs["timeout"] == custom_timeout
def test_call_endpoint_timeout_with_environment_variable(monkeypatch):
custom_timeout = 420
monkeypatch.setenv("MLFLOW_DEPLOYMENT_CLIENT_HTTP_REQUEST_TIMEOUT", str(custom_timeout))
client = get_deploy_client("http://localhost:5000")
with mock.patch("mlflow.deployments.mlflow.http_request") as mock_http_request:
mock_http_request.return_value.json.return_value = {"test": "response"}
mock_http_request.return_value.status_code = 200
client._call_endpoint("GET", "/test")
mock_http_request.assert_called_once()
call_args = mock_http_request.call_args
assert call_args.kwargs["timeout"] == custom_timeout
def test_get_endpoint_uses_deployment_client_timeout():
client = get_deploy_client("http://localhost:5000")
with mock.patch("mlflow.deployments.mlflow.http_request") as mock_http_request:
mock_http_request.return_value.json.return_value = {
"model": {"name": "gpt-4", "provider": "openai"},
"name": "test",
"endpoint_type": "llm/v1/chat",
"endpoint_url": "http://localhost:5000/endpoints/test/invocations",
"limit": None,
}
mock_http_request.return_value.status_code = 200
client.get_endpoint("test")
mock_http_request.assert_called_once()
call_args = mock_http_request.call_args
assert call_args.kwargs["timeout"] == MLFLOW_DEPLOYMENT_CLIENT_HTTP_REQUEST_TIMEOUT.get()
def test_list_endpoints_uses_deployment_client_timeout():
client = get_deploy_client("http://localhost:5000")
with mock.patch("mlflow.deployments.mlflow.http_request") as mock_http_request:
mock_http_request.return_value.json.return_value = {"endpoints": []}
mock_http_request.return_value.status_code = 200
client.list_endpoints()
mock_http_request.assert_called_once()
call_args = mock_http_request.call_args
assert call_args.kwargs["timeout"] == MLFLOW_DEPLOYMENT_CLIENT_HTTP_REQUEST_TIMEOUT.get()