add support for empty version and score route (#1995)

This commit is contained in:
Colin Versteeg 2019-10-04 22:53:11 -07:00 committed by Changming Sun
parent a9e04a29b3
commit 1ba76c5f74
5 changed files with 50 additions and 11 deletions

View file

@ -121,11 +121,6 @@ http::status HttpSession::ExecuteUserFunction(HttpContext& context) {
context.client_request_id = context.request[util::MS_CLIENT_REQUEST_ID_HEADER].to_string();
}
if (path == "/score") {
// This is a shortcut since we have only one model instance currently.
// This code path will be removed once we start supporting multiple models or multiple versions of one model.
path = "/v1/models/default/versions/1:predict";
}
auto status = routes_.ParseUrl(context.request.method(), path, model_name, model_version, action, func);

View file

@ -39,6 +39,9 @@ void Predict(const std::string& name,
auto logger = env->GetLogger(context.request_id);
logger->info("Model Name: {}, Version: {}, Action: {}", name, version, action);
auto effective_name = name.empty() ? "default" : name;
auto effective_version = version.empty() ? "1" : version;
if (!context.client_request_id.empty()) {
logger->info("{}: [{}]", util::MS_CLIENT_REQUEST_ID_HEADER, context.client_request_id);
}
@ -64,7 +67,7 @@ void Predict(const std::string& name,
// Run Prediction
Executor executor(env.get(), context.request_id);
PredictResponse predict_response{};
auto status = executor.Predict(name, version, predict_request, predict_response);
auto status = executor.Predict(effective_name, effective_version, predict_request, predict_response);
if (!status.ok()) {
GenerateErrorResponse(logger, GetHttpStatusCode((status)), status.error_message(), context);
return;

View file

@ -104,7 +104,7 @@ int main(int argc, char* argv[]) {
});
app.RegisterPost(
R"(/v1/models/([^/:]+)(?:/versions/(\d+))?:(classify|regress|predict))",
R"(/(?:v1/models/([^/:]+)(?:/versions/(\d+))?:(classify|regress|predict))|score)",
[&env](const auto& name, const auto& version, const auto& action, auto& context) -> void {
server::Predict(name, version, action, context, env);
});

View file

@ -192,6 +192,50 @@ class HttpJsonPayloadTests(unittest.TestCase):
for i in range(0, 10):
self.assertTrue(test_util.compare_floats(actual_data[i], expected_data[i]))
def test_single_version_shortcut(self):
input_data_file = os.path.join(self.test_data_path, 'mnist_test_data_set_0_input.json')
output_data_file = os.path.join(self.test_data_path, 'mnist_test_data_set_0_output.json')
with open(input_data_file, 'r') as f:
request_payload = f.read()
with open(output_data_file, 'r') as f:
expected_response_json = f.read()
expected_response = json.loads(expected_response_json)
request_headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'x-ms-client-request-id': 'This~is~my~id'
}
url = "http://{0}:{1}/v1/models/{2}:predict".format(self.server_ip, self.server_port, 'default_model')
test_util.test_log(url)
r = requests.post(url, headers=request_headers, data=request_payload)
self.assertEqual(r.status_code, 200)
self.assertEqual(r.headers.get('Content-Type'), 'application/json')
self.assertTrue(r.headers.get('x-ms-request-id'))
self.assertEqual(r.headers.get('x-ms-client-request-id'), 'This~is~my~id')
actual_response = json.loads(r.content.decode('utf-8'))
# Note:
# The 'dims' field is defined as "repeated int64" in protobuf.
# When it is serialized to JSON, all int64/fixed64/uint64 numbers are converted to string
# Reference: https://developers.google.com/protocol-buffers/docs/proto3#json
self.assertTrue(actual_response['outputs'])
self.assertTrue(actual_response['outputs']['Plus214_Output_0'])
self.assertTrue(actual_response['outputs']['Plus214_Output_0']['dims'])
self.assertEqual(actual_response['outputs']['Plus214_Output_0']['dims'], ['1', '10'])
self.assertTrue(actual_response['outputs']['Plus214_Output_0']['dataType'])
self.assertEqual(actual_response['outputs']['Plus214_Output_0']['dataType'], 1)
self.assertTrue(actual_response['outputs']['Plus214_Output_0']['rawData'])
actual_data = test_util.decode_base64_string(actual_response['outputs']['Plus214_Output_0']['rawData'], '10f')
expected_data = test_util.decode_base64_string(expected_response['outputs']['Plus214_Output_0']['rawData'], '10f')
for i in range(0, 10):
self.assertTrue(test_util.compare_floats(actual_data[i], expected_data[i]))
class HttpProtobufPayloadTests(unittest.TestCase):
server_ip = '127.0.0.1'

View file

@ -10,6 +10,7 @@ namespace onnxruntime {
namespace server {
namespace test {
static const std::string predict_regex = R"(/v1/models/([^/:]+)(?:/versions/(\d+))?:(classify|regress|predict))";
using test_data = std::tuple<http::verb, std::string, std::string, std::string, std::string, http::status>;
void do_something(const std::string& name, const std::string& version,
@ -20,7 +21,6 @@ void do_something(const std::string& name, const std::string& version,
void run_route(const std::string& pattern, http::verb method, const std::vector<test_data>& data, bool does_validate_data);
TEST(HttpRouteTests, RegisterTest) {
auto predict_regex = R"(/v1/models/([^/:]+)(?:/versions/(\d+))?:(classify|regress|predict))";
Routes routes;
EXPECT_TRUE(routes.RegisterController(http::verb::post, predict_regex, do_something));
@ -29,7 +29,6 @@ TEST(HttpRouteTests, RegisterTest) {
}
TEST(HttpRouteTests, PostRouteTest) {
auto predict_regex = R"(/v1/models/([^/:]+)(?:/versions/(\d+))?:(classify|regress|predict))";
std::vector<test_data> actions{
std::make_tuple(http::verb::post, "/v1/models/abc/versions/23:predict", "abc", "23", "predict", http::status::ok),
@ -42,7 +41,6 @@ TEST(HttpRouteTests, PostRouteTest) {
}
TEST(HttpRouteTests, PostRouteInvalidURLTest) {
auto predict_regex = R"(/v1/models/([^/:]+)(?:/versions/(\d+))?:(classify|regress|predict))";
std::vector<test_data> actions{
std::make_tuple(http::verb::post, "", "", "", "", http::status::not_found),
@ -66,7 +64,6 @@ TEST(HttpRouteTests, PostRouteInvalidURLTest) {
// These tests are because we currently only support POST and GET
// Some HTTP methods should be removed from test data if we support more (e.g. PUT)
TEST(HttpRouteTests, PostRouteInvalidMethodTest) {
auto predict_regex = R"(/v1/models/([^/:]+)(?:/versions/(\d+))?:(classify|regress|predict))";
std::vector<test_data> actions{
std::make_tuple(http::verb::get, "/v1/models/abc/versions/23:predict", "abc", "23", "predict", http::status::method_not_allowed),