diff --git a/testing/resources/s2i_python_model_non200.json b/testing/resources/s2i_python_model_non200.json new file mode 100644 index 0000000000..4d5286db02 --- /dev/null +++ b/testing/resources/s2i_python_model_non200.json @@ -0,0 +1,38 @@ +{ + "apiVersion": "machinelearning.seldon.io/v1alpha2", + "kind": "SeldonDeployment", + "metadata": { + "name": "mymodel" + }, + "spec": { + "name": "mymodel", + "oauth_key": "oauth-key", + "oauth_secret": "oauth-secret", + "predictors": [ + { + "componentSpecs": [{ + "spec": { + "containers": [ + { + "image": "seldonio/testmodel_rest_non200:0.1", + "imagePullPolicy": "Never", + "name": "model" + } + ], + "terminationGracePeriodSeconds": 1 + } + }], + "graph": { + "children": [], + "name": "model", + "endpoint": { + "type" : "REST" + }, + "type": "MODEL" + }, + "name": "mymodel", + "replicas": 1 + } + ] + } +} diff --git a/testing/s2i/python/model/MyModelNon200Response.py b/testing/s2i/python/model/MyModelNon200Response.py new file mode 100644 index 0000000000..83e40d564a --- /dev/null +++ b/testing/s2i/python/model/MyModelNon200Response.py @@ -0,0 +1,16 @@ +from flask.json import jsonify + + +class MyModelNon200Response(object): + def __init__(self, metrics_ok=True): + print("Init called") + + def predict_raw(self, message): + status = { + "code": 400, + "reason": "exception message", + "status": "FAILURE", + "info": "exception caught", + } + + return {"data": {"names": ["score"], "ndarray": []}, "status": status} diff --git a/testing/s2i/python/model/environment_rest_non200 b/testing/s2i/python/model/environment_rest_non200 new file mode 100644 index 0000000000..186f60e8ff --- /dev/null +++ b/testing/s2i/python/model/environment_rest_non200 @@ -0,0 +1,4 @@ +MODEL_NAME=MyModelNon200Response +API_TYPE=REST +SERVICE_TYPE=MODEL +PERSISTENCE=0 \ No newline at end of file diff --git a/testing/scripts/test_s2i_python.py b/testing/scripts/test_s2i_python.py index 64b0ac5385..a42b915218 100644 --- a/testing/scripts/test_s2i_python.py +++ b/testing/scripts/test_s2i_python.py @@ -115,6 +115,10 @@ def test_model_rest(self, s2i_python_version): tester = S2IK8S() tester.test_model_rest(s2i_python_version) + def test_model_rest_non200(self, s2i_python_version): + tester = S2IK8S() + tester.test_model_rest_non200(s2i_python_version) + def test_input_transformer_rest(self, s2i_python_version): tester = S2IK8S() tester.test_input_transformer_rest(s2i_python_version) @@ -153,6 +157,30 @@ def test_model_rest(self, s2i_python_version): ) run(f"kubectl delete namespace {namespace}", shell=True) + def test_model_rest_non200(self, s2i_python_version): + namespace = "s2i-test-model-rest-non200" + retry_run(f"kubectl create namespace {namespace}") + create_push_s2i_image(s2i_python_version, "model", "rest_non200") + retry_run( + f"kubectl apply -f ../resources/s2i_python_model_non200.json -n {namespace}" + ) + wait_for_rollout("mymodel-mymodel-4e3d66d", namespace) + r = initial_rest_request("mymodel", namespace) + arr = np.array([[1, 2, 3]]) + r = rest_request_ambassador("mymodel", namespace, API_AMBASSADOR, data=arr) + res = r.json() + logging.warning(res) + assert r.status_code == 200 + assert r.json()["status"]["code"] == 400 + assert r.json()["status"]["reason"] == "exception message" + assert r.json()["status"]["info"] == "exception caught" + assert r.json()["status"]["status"] == "FAILURE" + run( + f"kubectl delete -f ../resources/s2i_python_model_non200.json -n {namespace}", + shell=True, + ) + run(f"kubectl delete namespace {namespace}", shell=True) + def test_input_transformer_rest(self, s2i_python_version): namespace = "s2i-test-input-transformer-rest" retry_run(f"kubectl create namespace {namespace}")