Browse Source

serving, ut5

tags/v1.2.0
xuyongfei 5 years ago
parent
commit
ca0bb64cd0
25 changed files with 2693 additions and 262 deletions
  1. +3
    -3
      cmake/external_libs/glog.cmake
  2. +12
    -6
      mindspore_serving/ccsrc/common/proto_tensor.cc
  3. +0
    -3
      mindspore_serving/ccsrc/common/status.h
  4. +1
    -1
      mindspore_serving/ccsrc/common/tensor_base.cc
  5. +2
    -2
      mindspore_serving/ccsrc/common/tensor_base.h
  6. +3
    -5
      mindspore_serving/ccsrc/master/restful/http_handle.cc
  7. +47
    -46
      mindspore_serving/ccsrc/master/restful/http_process.cc
  8. +42
    -50
      mindspore_serving/ccsrc/master/restful/restful_request.cc
  9. +2
    -10
      mindspore_serving/ccsrc/master/restful/restful_server.cc
  10. +3
    -0
      mindspore_serving/ccsrc/python/serving_py.cc
  11. +3
    -3
      mindspore_serving/ccsrc/python/tensor_py.cc
  12. +7
    -30
      mindspore_serving/client/python/client.py
  13. +5
    -5
      mindspore_serving/log.py
  14. +0
    -1
      mindspore_serving/master/__init__.py
  15. +2
    -0
      requirements_test.txt
  16. +4
    -13
      tests/ut/CMakeLists.txt
  17. +5
    -2
      tests/ut/cpp/runtest.sh
  18. +13
    -2
      tests/ut/cpp/tests/parse_restful.cc
  19. +4
    -2
      tests/ut/python/runtest.sh
  20. +38
    -0
      tests/ut/python/tests/common.py
  21. +75
    -0
      tests/ut/python/tests/common_restful.py
  22. +98
    -78
      tests/ut/python/tests/test_mater_worker_client.py
  23. +949
    -0
      tests/ut/python/tests/test_restful_base64_data.py
  24. +1040
    -0
      tests/ut/python/tests/test_restful_json_data.py
  25. +335
    -0
      tests/ut/python/tests/test_restful_request.py

+ 3
- 3
cmake/external_libs/glog.cmake View File

@@ -1,12 +1,12 @@
set(glog_CXXFLAGS "-D_FORTIFY_SOURCE=2 -O2 ${SECURE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0")
set(glog_CFLAGS "-D_FORTIFY_SOURCE=2 -O2")
if (ENABLE_GITEE)
if(ENABLE_GITEE)
set(REQ_URL "https://gitee.com/mirrors/glog/repository/archive/v0.4.0.tar.gz")
set(MD5 "22fe340ddc231e6c8e46bc295320f8ee")
else()
set(REQ_URL "https://github.com/google/glog/archive/v0.4.0.tar.gz")
set(MD5 "0daea8785e6df922d7887755c3d100d0")
endif ()
endif()
mindspore_add_pkg(glog
VER 0.4.0
LIBS glog
@@ -14,4 +14,4 @@ mindspore_add_pkg(glog
MD5 ${MD5}
CMAKE_OPTION -DBUILD_TESTING=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DBUILD_SHARED_LIBS=ON -DWITH_GFLAGS=OFF)
include_directories(${glog_INC})
add_library(mindspore::glog ALIAS glog::glog)
add_library(mindspore_serving::glog ALIAS glog::glog)

+ 12
- 6
mindspore_serving/ccsrc/common/proto_tensor.cc View File

@@ -241,7 +241,7 @@ Status GrpcTensorHelper::CreateInstanceFromRequest(const proto::PredictRequest &
MethodSignature method_signature;
if (!servable_signature.GetMethodDeclare(request_spec->method_name, &method_signature)) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS)
<< "Method " << method_name << " is not registed for servable " << servable_name;
<< "Method " << method_name << " is not registered for servable " << servable_name;
}

if (request.instances_size() == 0) {
@@ -269,7 +269,7 @@ Status GrpcTensorHelper::CreateReplyFromInstances(const proto::PredictRequest &r
MethodSignature method_signature;
if (!servable_signature.GetMethodDeclare(method_name, &method_signature)) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS)
<< "Method " << method_name << " is not registed for servable " << servable_name;
<< "Method " << method_name << " is not registered for servable " << servable_name;
}
*reply->mutable_servable_spec() = request.servable_spec();

@@ -305,7 +305,7 @@ Status GrpcTensorHelper::CreateReplyFromInstances(const proto::PredictRequest &r
auto &output_tensor = output_intance.data[i];
auto &proto_tensor = (*proto_items)[method_signature.outputs[i]];
ProtoTensor result_tensor(&proto_tensor);
result_tensor.assgin(*output_tensor);
result_tensor.assign(*output_tensor);
}
}
return SUCCESS;
@@ -356,9 +356,15 @@ Status GrpcTensorHelper::CheckRequestTensor(const proto::Tensor &tensor) {
}
} else {
size_t element_num = tensor_input.element_cnt();
if (element_num == 0) { // shape dim invalid or element count > max element num
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "Tensor check failed: input "
<< " shape " << tensor_input.shape() << " invalid";
bool zero_dim = false;
for (auto &shape_item : tensor_input.shape()) {
if (shape_item < 0 || zero_dim) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "Tensor check failed: input "
<< " shape " << tensor_input.shape() << " invalid";
}
if (shape_item == 0) {
zero_dim = true;
}
}
if (tensor_input.data_type() == kMSI_Unknown || tensor_input.itemsize() == 0) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "Tensor check failed: input "


+ 0
- 3
mindspore_serving/ccsrc/common/status.h View File

@@ -63,9 +63,6 @@ class Status {
}

#define INFER_STATUS(code) mindspore::serving::Status(code) < mindspore::serving::LogStream()
#define ERROR_INFER_STATUS(status, type, msg) \
MSI_LOG_ERROR << msg; \
status = mindspore::serving::Status(type, msg)

#define INFER_STATUS_LOG_ERROR(code) mindspore::serving::Status(code) = MSILOG_NOIF(ERROR)
#define INFER_STATUS_LOG_WARNING(code) mindspore::serving::Status(code) = MSILOG_NOIF(WARNING)


+ 1
- 1
mindspore_serving/ccsrc/common/tensor_base.cc View File

@@ -68,7 +68,7 @@ size_t TensorBase::GetTypeSize(DataType type) {
return 0;
}

void TensorBase::assgin(const TensorBase &other) {
void TensorBase::assign(const TensorBase &other) {
if (is_bytes_val_data()) {
clear_bytes_data();
}


+ 2
- 2
mindspore_serving/ccsrc/common/tensor_base.h View File

@@ -51,7 +51,7 @@ enum DataType {
class TensorBase;
using TensorBasePtr = std::shared_ptr<TensorBase>;

class MS_API TensorBase {
class MS_API TensorBase : public std::enable_shared_from_this<TensorBase> {
public:
TensorBase() = default;
virtual ~TensorBase() = default;
@@ -84,7 +84,7 @@ class MS_API TensorBase {

// TensorBase(const TensorBase& other) = delete;
// TensorBase& operator=(const TensorBase& other) = delete;
void assgin(const TensorBase &other);
void assign(const TensorBase &other);
Status concat(const std::vector<TensorBasePtr> &inputs);
bool is_bytes_val_data() const { return data_type() == kMSI_Bytes || data_type() == kMSI_String; }
};


+ 3
- 5
mindspore_serving/ccsrc/master/restful/http_handle.cc View File

@@ -120,18 +120,16 @@ size_t GetB64OriginSize(size_t target_len, size_t tail_size) {

size_t GetTailEqualSize(const std::string &str) {
size_t length = str.size();
if (length == 0 || length % 4 != 0) {
if (length % 4 != 0) {
return UINT32_MAX;
}
size_t count = 0;
if (str.at(str.size() - 1) == '=') {
if (length >= 1 && str[length - 1] == '=') {
count++;
}

if (str.at(str.size() - 2) == '=') {
if (length >= 2 && str[length - 2] == '=') {
count++;
}

return count;
}



+ 47
- 46
mindspore_serving/ccsrc/master/restful/http_process.cc View File

@@ -148,8 +148,9 @@ bool RestfulService::JsonMatchDataType(const json &js, DataType type) {
flag = true;
}
} else if (js.is_string()) {
// string value can express all kinds type
flag = true;
if (type == kMSI_String) {
flag = true;
}
} else if (js.is_boolean()) {
if (type == kMSI_Bool) {
flag = true;
@@ -162,12 +163,9 @@ bool RestfulService::JsonMatchDataType(const json &js, DataType type) {
std::vector<int64_t> RestfulService::GetObjShape(const json &js) {
std::vector<int64_t> shape;
auto it = js.find(kShape);
if (it == js.end()) {
shape.push_back(1);
} else {
if (it != js.end()) {
shape = GetSpecifiedShape(it.value());
}

return shape;
}

@@ -330,17 +328,24 @@ Status RestfulService::CheckObj(const json &js) {
if (!value.is_array()) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "json object, key is 'shape', value should be array type";
}
if (value.empty()) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "json object, key is 'shape', array value should no be empty";
}
bool zero_dims_before = false;
for (auto it = value.begin(); it != value.end(); ++it) {
if (!(it->is_number())) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "json object, key is 'shape', array value should be number";
if (zero_dims_before) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS)
<< "json object, key is 'shape', invalid shape value " << value.dump();
}
if (!(it->is_number_unsigned())) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS)
<< "json object, key is 'shape', array value should be unsigned integer";
}
auto number = it->get<int32_t>();
if (number <= 0) {
if (number < 0) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS)
<< "json object, key is 'shape', number value should be positive number";
<< "json object, key is 'shape', number value should not be negative number, shape value: "
<< value.dump();
}
if (number == 0) {
zero_dims_before = true;
}
}
shape_count++;
@@ -365,28 +370,29 @@ Status RestfulService::CheckObj(const json &js) {
// 1. parse request common func
Status RestfulService::ParseItem(const json &value, ProtoTensor *const pb_tensor) {
Status status(SUCCESS);
std::vector<int64_t> scalar_shape = {};
if (value.is_number_integer()) {
DataType type = kMSI_Int32;
pb_tensor->set_data_type(type);
pb_tensor->set_shape({1});
pb_tensor->set_shape(scalar_shape);
pb_tensor->resize_data(pb_tensor->GetTypeSize(type));
status = GetScalarByType(type, value, 0, pb_tensor);
} else if (value.is_number_float()) {
DataType type = kMSI_Float32;
pb_tensor->set_data_type(type);
pb_tensor->set_shape({1});
pb_tensor->set_shape(scalar_shape);
pb_tensor->resize_data(pb_tensor->GetTypeSize(type));
status = GetScalarByType(type, value, 0, pb_tensor);
} else if (value.is_boolean()) {
DataType type = kMSI_Bool;
pb_tensor->set_data_type(type);
pb_tensor->set_shape({1});
pb_tensor->set_shape(scalar_shape);
pb_tensor->resize_data(pb_tensor->GetTypeSize(type));
status = GetScalarByType(type, value, 0, pb_tensor);
} else if (value.is_string()) {
DataType type = kMSI_String;
pb_tensor->set_data_type(type);
pb_tensor->set_shape({1});
pb_tensor->set_shape(scalar_shape);
status = GetScalarByType(type, value, 0, pb_tensor);
} else if (value.is_object()) {
status = CheckObj(value);
@@ -400,10 +406,6 @@ Status RestfulService::ParseItem(const json &value, ProtoTensor *const pb_tensor
}

std::vector<int64_t> shape = GetObjShape(value);
if (shape.empty()) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "object json, shape is empty";
}

bool is_tensor = false;
if (type != kMSI_String && type != kMSI_Bytes) {
is_tensor = true;
@@ -437,7 +439,7 @@ Status RestfulService::ParseItem(const json &value, ProtoTensor *const pb_tensor
is_tensor = true;
}

// intances mode:only support one item
// instances mode:only support one item
if (request_type_ == kInstanceType) {
if (!is_tensor) {
size_t elements_nums = std::accumulate(shape.begin(), shape.end(), 1LL, std::multiplies<size_t>());
@@ -481,15 +483,15 @@ Status RestfulService::RecursiveGetArray(const json &json_data, size_t depth, si
std::vector<int64_t> required_shape = request_tensor->shape();
if (depth >= required_shape.size()) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS)
<< "current depth:" << depth << " is more than shape dims:" << required_shape.size();
<< "invalid json array: current depth " << depth << " is more than shape dims " << required_shape.size();
}
if (!json_data.is_array()) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "json type is not array";
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "invalid json array: json type is not array";
}
if (json_data.size() != static_cast<size_t>(required_shape[depth])) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS)
<< "json size is:" << json_data.size() << "; the " << depth << " dim need"
<< " shape size:" << required_shape[depth];
<< "invalid json array: json size is " << json_data.size() << ", the dim " << depth << " expected to be "
<< required_shape[depth];
}
if (depth + 1 < required_shape.size()) {
size_t sub_element_cnt =
@@ -618,9 +620,7 @@ Status RestfulService::GetScalarData(const json &js, size_t index, bool is_bytes

auto value = js.get<std::string>();
if (is_bytes) {
if (value.empty()) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "string value is empty";
}
DataType real_type = request_tensor->data_type();
auto tail_equal_size = GetTailEqualSize(value);
if (tail_equal_size == UINT32_MAX) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "'" << value << "' is illegal b64 encode string";
@@ -631,7 +631,6 @@ Status RestfulService::GetScalarData(const json &js, size_t index, bool is_bytes
if (target_size != origin_size) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "decode base64 failed, size is not matched.";
}
DataType real_type = request_tensor->data_type();
if (real_type == kMSI_Bytes || real_type == kMSI_String) {
request_tensor->add_bytes_data(buffer.data(), origin_size);
} else {
@@ -643,9 +642,10 @@ Status RestfulService::GetScalarData(const json &js, size_t index, bool is_bytes
<< "; Given info: type:" << GetStringByDataType(real_type) << "; type size:" << type_size
<< "; element nums:" << element_cnt;
}

auto data = reinterpret_cast<T *>(request_tensor->mutable_data()) + index;
memcpy_s(data, origin_size, buffer.data(), buffer.size());
if (origin_size > 0) {
auto data = reinterpret_cast<T *>(request_tensor->mutable_data()) + index;
memcpy_s(data, origin_size, buffer.data(), buffer.size());
}
}
} else {
request_tensor->add_bytes_data(reinterpret_cast<uint8_t *>(value.data()), value.length());
@@ -680,7 +680,7 @@ Status RestfulService::RunRestful(const std::shared_ptr<RestfulRequest> &restful
MSI_TIME_STAMP_END(ParseRequest)
if (status != SUCCESS) {
std::string error_msg = status.StatusMessage();
std::string msg = "Parser reqeust failed, " + error_msg;
std::string msg = "Parser request failed, " + error_msg;
status = msg;
return status;
}
@@ -730,7 +730,7 @@ Status RestfulService::ParseRequest(const std::shared_ptr<RestfulRequest> &restf
status = ParseInstancesMsg(js_msg, request);
break;
default:
return INFER_STATUS_LOG_ERROR(FAILED) << "restful reqeust only support instances mode";
return INFER_STATUS_LOG_ERROR(FAILED) << "restful request only support instances mode";
}

return status;
@@ -741,8 +741,7 @@ Status RestfulService::ParseReqCommonMsg(const std::shared_ptr<RestfulRequest> &
Status status(SUCCESS);
auto request_ptr = restful_request->decompose_event_request();
if (request_ptr == nullptr) {
ERROR_INFER_STATUS(status, INVALID_INPUTS, "Decompose event request is nullptr");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "Decompose event request is nullptr";
}
request->mutable_servable_spec()->set_name(request_ptr->model_name_);
request->mutable_servable_spec()->set_version_number(request_ptr->version_);
@@ -755,8 +754,7 @@ Status RestfulService::ParseInstancesMsg(const json &js_msg, PredictRequest *con
auto type = GetReqTypeStr(request_type_);
auto instances = js_msg.find(type);
if (instances == js_msg.end()) {
ERROR_INFER_STATUS(status, FAILED, "instances request json should have instances key word");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "instances request json should have instances key word";
}

// get instances way:{key, value} or {value}
@@ -845,9 +843,7 @@ Status RestfulService::ParseReplyDetail(const proto::Tensor &tensor, json *const
Status status(SUCCESS);
const ProtoTensor pb_tensor(const_cast<proto::Tensor *>(&tensor));
auto shape = pb_tensor.shape();
size_t shape_size = std::accumulate(shape.begin(), shape.end(), 1LL, std::multiplies<size_t>());

if (shape_size == 1) {
if (shape.empty()) {
status = ParseScalar(pb_tensor, 0, js);
if (status != SUCCESS) {
return status;
@@ -900,7 +896,7 @@ Status RestfulService::ParseScalar(const ProtoTensor &pb_tensor, size_t index, j
status = ParseScalarData<uint64_t>(pb_tensor, false, index, js);
break;
case kMSI_Float16:
ERROR_INFER_STATUS(status, FAILED, "fp16 reply is not supported");
status = INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "fp16 reply is not supported";
break;
case kMSI_Float32:
status = ParseScalarData<float>(pb_tensor, false, index, js);
@@ -915,7 +911,7 @@ Status RestfulService::ParseScalar(const ProtoTensor &pb_tensor, size_t index, j
status = ParseScalarData<std::string>(pb_tensor, true, index, js);
break;
default:
ERROR_INFER_STATUS(status, FAILED, "reply data type is not supported");
status = INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "reply data type is not supported";
break;
}
return status;
@@ -981,10 +977,15 @@ Status RestfulService::RecursiveParseArray(const ProtoTensor &pb_tensor, size_t
json *const out_json) {
Status status(SUCCESS);
std::vector<int64_t> required_shape = pb_tensor.shape();
if (depth >= 10) {
return INFER_STATUS_LOG_ERROR(FAILED) << "result shape dims is larger than 10";
if (depth >= required_shape.size()) {
return INFER_STATUS_LOG_ERROR(FAILED)
<< "result shape dims is larger than result shape size " << required_shape.size();
}
if (depth == required_shape.size() - 1) {
if (required_shape[depth] == 0) { // make empty array
out_json->push_back(json());
out_json->clear();
}
for (int i = 0; i < required_shape[depth]; i++) {
out_json->push_back(json());
json &scalar_json = out_json->back();


+ 42
- 50
mindspore_serving/ccsrc/master/restful/restful_request.cc View File

@@ -21,10 +21,12 @@
#include <algorithm>
#include <utility>

static const char UrlKeyModel[] = "model";
static const char UrlKeyVersion[] = "version";
static const char UrlSplit[] = "/";
static const char UrlKeyEnd[] = ":";
namespace {
const char kUrlKeyModel[] = "model";
const char kUrlKeyVersion[] = "version";
const char kUrlSplit[] = "/";
const char kUrlKeyEnd[] = ":";
} // namespace

namespace mindspore {
namespace serving {
@@ -40,8 +42,8 @@ DecomposeEvRequest::~DecomposeEvRequest() {

std::string DecomposeEvRequest::UrlQuery(const std::string &url, const std::string &key) {
std::string::size_type start_pos(0);
if (key == UrlKeyEnd) {
if ((start_pos = url_.find(UrlKeyEnd)) != std::string::npos) {
if (key == kUrlKeyEnd) {
if ((start_pos = url_.find(kUrlKeyEnd)) != std::string::npos) {
return url_.substr(start_pos + 1, url_.size());
}
}
@@ -49,10 +51,11 @@ std::string DecomposeEvRequest::UrlQuery(const std::string &url, const std::stri
int key_size = key.size() + 1;
std::string::size_type end_pos(0);
if ((start_pos = url.find(key)) != std::string::npos) {
end_pos = std::min(url.find(UrlSplit, start_pos + key_size), url.find(UrlKeyEnd, start_pos + key_size));
if (end_pos != std::string::npos) {
return url.substr(start_pos + key_size, end_pos - start_pos - key_size);
end_pos = std::min(url.find(kUrlSplit, start_pos + key_size), url.find(kUrlKeyEnd, start_pos + key_size));
if (end_pos == std::string::npos) {
return url.substr(start_pos + key_size);
}
return url.substr(start_pos + key_size, end_pos - start_pos - key_size);
}
return "";
}
@@ -62,21 +65,17 @@ Status DecomposeEvRequest::GetPostMessageToJson() {
std::string message;
size_t input_size = evbuffer_get_length(event_request_->input_buffer);
if (input_size == 0) {
ERROR_INFER_STATUS(status, INVALID_INPUTS, "http message invalid");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "http message invalid";
} else if (input_size > max_msg_size_) {
ERROR_INFER_STATUS(status, INVALID_INPUTS, "http message is bigger than " + std::to_string(max_msg_size_));
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "http message is bigger than " << max_msg_size_;
} else {
message.resize(input_size);
auto src_data = evbuffer_pullup(event_request_->input_buffer, -1);
if (src_data == nullptr) {
ERROR_INFER_STATUS(status, FAILED, "get http message failed.");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "get http message failed.";
}
if (memcpy_s(message.data(), input_size, src_data, input_size) != EOK) {
ERROR_INFER_STATUS(status, FAILED, "copy http message failed.");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "copy http message failed.";
}
}
MSI_TIME_STAMP_START(ParseJson)
@@ -84,9 +83,7 @@ Status DecomposeEvRequest::GetPostMessageToJson() {
request_message_ = nlohmann::json::parse(message);
} catch (nlohmann::json::exception &e) {
std::string json_exception = e.what();
std::string error_message = "Illegal JSON format." + json_exception;
ERROR_INFER_STATUS(status, INVALID_INPUTS, error_message);
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "Illegal JSON format." + json_exception;
}
MSI_TIME_STAMP_END(ParseJson)

@@ -100,8 +97,7 @@ Status DecomposeEvRequest::CheckRequestMethodValid() {
request_method_ = "POST";
return status;
default:
ERROR_INFER_STATUS(status, INVALID_INPUTS, "http message only support POST right now");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "http message only support POST right now";
}
}

@@ -120,35 +116,37 @@ Status DecomposeEvRequest::Decompose() {
// eg: /model/resnet/version/1:predict
url_ = evhttp_request_get_uri(event_request_);
if (url_.empty()) {
ERROR_INFER_STATUS(status, INVALID_INPUTS, "evhttp url is empty.");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "evhttp url is empty.";
}
MSI_LOG_INFO << "url_: " << url_;

model_name_ = UrlQuery(url_, UrlKeyModel);
model_name_ = UrlQuery(url_, kUrlKeyModel);
if (model_name_.empty()) {
ERROR_INFER_STATUS(status, INVALID_INPUTS, "please check url, the keyword:[model] must contain.");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "please check url, the keyword:[model] must contain.";
}
MSI_LOG_INFO << "model_name_: " << model_name_;
if (url_.find(UrlKeyVersion) != std::string::npos) {
auto version_str = UrlQuery(url_, UrlKeyVersion);
if (url_.find(kUrlKeyVersion) != std::string::npos) {
auto version_str = UrlQuery(url_, kUrlKeyVersion);
try {
version_ = std::stol(version_str);
auto version = std::stol(version_str);
if (version < 0 || version >= UINT32_MAX) {
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS)
<< "please check url, version number range failed, request version number " << version_str;
}
version_ = static_cast<uint32_t>(version);
} catch (const std::invalid_argument &) {
ERROR_INFER_STATUS(status, INVALID_INPUTS, "please check url, the keyword:[version] must contain.");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS)
<< "please check url, the keyword:[version] value invalid, request version number " << version_str;
} catch (const std::out_of_range &) {
ERROR_INFER_STATUS(status, INVALID_INPUTS, "please check url, the keyword:[version] out of range.");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS)
<< "please check url, version number range failed, request version number " << version_str;
}
MSI_LOG_INFO << "version_: " << version_;
}

service_method_ = UrlQuery(url_, UrlKeyEnd);
service_method_ = UrlQuery(url_, kUrlKeyEnd);
if (service_method_.empty()) {
ERROR_INFER_STATUS(status, INVALID_INPUTS, "please check url, the keyword:[service method] must contain.");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "please check url, the keyword:[service method] must contain.";
}
MSI_LOG_INFO << "service_method_: " << service_method_;
return status;
@@ -164,37 +162,31 @@ RestfulRequest::~RestfulRequest() {
}

Status RestfulRequest::RestfulReplayBufferInit() {
Status status(SUCCESS);
replay_buffer_ = evbuffer_new();
if (replay_buffer_ == nullptr) {
ERROR_INFER_STATUS(status, INVALID_INPUTS, "creat restful replay buffer fail");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "create restful replay buffer fail";
}
return status;
return SUCCESS;
}

Status RestfulRequest::RestfulReplay(const std::string &replay) {
Status status(SUCCESS);
if (replay_buffer_ == nullptr) {
ERROR_INFER_STATUS(status, INVALID_INPUTS, "replay_buffer_ is nullptr");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "replay_buffer_ is nullptr";
}
if (decompose_event_request_ == nullptr) {
ERROR_INFER_STATUS(status, INVALID_INPUTS, "replay_buffer_ is nullptr");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "replay_buffer_ is nullptr";
}
if (decompose_event_request_->event_request_ == nullptr) {
ERROR_INFER_STATUS(status, INVALID_INPUTS, "replay_buffer_ is nullptr");
return status;
return INFER_STATUS_LOG_ERROR(INVALID_INPUTS) << "replay_buffer_ is nullptr";
}
evbuffer_add(replay_buffer_, replay.data(), replay.size());
evhttp_send_reply(decompose_event_request_->event_request_, HTTP_OK, "Client", replay_buffer_);
return status;
return SUCCESS;
}

Status RestfulRequest::ErrorMessage(Status status) {
Status error_status(SUCCESS);
nlohmann::json error_json = {{"error_message", status.StatusMessage()}};
nlohmann::json error_json = {{"error_msg", status.StatusMessage()}};
std::string out_error_str = error_json.dump();
if ((error_status = RestfulReplay(out_error_str)) != SUCCESS) {
return error_status;


+ 2
- 10
mindspore_serving/ccsrc/master/restful/restful_server.cc View File

@@ -46,16 +46,8 @@ void RestfulServer::DispatchEvHttpRequest(evhttp_request *request) {
Status status(SUCCESS);

auto de_request = std::make_unique<DecomposeEvRequest>(request, max_msg_size_);
if (de_request == nullptr) {
ERROR_INFER_STATUS(status, INVALID_INPUTS, "de_request is nullptr.");
return;
}
Status de_status = de_request->Decompose();
auto restful_request = std::make_shared<RestfulRequest>(std::move(de_request));
if (restful_request == nullptr) {
ERROR_INFER_STATUS(status, INVALID_INPUTS, "restful_request is nullptr.");
return;
}
status = restful_request->RestfulReplayBufferInit();
if (status != SUCCESS) {
if ((status = restful_request->ErrorMessage(status)) != SUCCESS) {
@@ -129,7 +121,7 @@ Status RestfulServer::StartRestfulServer() {

if (listener == nullptr) {
status = INFER_STATUS_LOG_ERROR(SYSTEM_ERROR)
<< "Serving Error: RESTful server start failed, create http listener faild, port " << restful_port_;
<< "Serving Error: RESTful server start failed, create http listener failed, port " << restful_port_;
free_event_base();
free_evhttp();
return status;
@@ -137,7 +129,7 @@ Status RestfulServer::StartRestfulServer() {
auto bound = evhttp_bind_listener(event_http_, listener);
if (bound == nullptr) {
status = INFER_STATUS_LOG_ERROR(SYSTEM_ERROR)
<< "Serving Error: RESTful server start failed, bind http listener to server faild, port "
<< "Serving Error: RESTful server start failed, bind http listener to server failed, port "
<< restful_port_;
evconnlistener_free(listener);
free_event_base();


+ 3
- 0
mindspore_serving/ccsrc/python/serving_py.cc View File

@@ -27,6 +27,9 @@
namespace mindspore::serving {

PYBIND11_MODULE(_mindspore_serving, m) {
// avoid as numpy object memory copy in PyTensor::AsPythonData
py::class_<TensorBase, TensorBasePtr>(m, "Tensor_");

py::class_<PyPreprocessStorage, std::shared_ptr<PyPreprocessStorage>>(m, "PreprocessStorage_")
.def(py::init<>())
.def_static("get_instance", &PyPreprocessStorage::Instance)


+ 3
- 3
mindspore_serving/ccsrc/python/tensor_py.cc View File

@@ -196,7 +196,7 @@ py::object PyTensor::AsPythonData(TensorBasePtr tensor, bool copy) {
py::buffer_info info(reinterpret_cast<void *>(const_cast<uint8_t *>(data)), sizeof(uint8_t),
py::format_descriptor<uint8_t>::format(), 1, shape, strides);
if (!copy) {
py::array self;
py::object self = py::cast(tensor.get());
return py::array(py::dtype(info), info.shape, info.strides, info.ptr, self);
} else {
return py::array(py::dtype(info), info.shape, info.strides, info.ptr);
@@ -210,7 +210,7 @@ py::object PyTensor::AsPythonData(TensorBasePtr tensor, bool copy) {
static_cast<ssize_t>(tensor_shape.size()), shape, strides);

if (!copy) {
py::array self;
py::object self = py::cast(tensor.get());
return py::array(py::dtype(info), info.shape, info.strides, info.ptr, self);
} else {
return py::array(py::dtype(info), info.shape, info.strides, info.ptr);
@@ -221,7 +221,7 @@ py::object PyTensor::AsPythonData(TensorBasePtr tensor, bool copy) {
py::tuple PyTensor::AsNumpyTuple(const InstanceData &instance_data) {
py::tuple numpy_inputs_tuple(instance_data.size());
for (size_t i = 0; i < instance_data.size(); i++) { // inputs
numpy_inputs_tuple[i] = PyTensor::AsPythonData(instance_data[i]);
numpy_inputs_tuple[i] = PyTensor::AsPythonData(instance_data[i], false);
}
return numpy_inputs_tuple;
}


+ 7
- 30
mindspore_serving/client/python/client.py View File

@@ -126,17 +126,17 @@ def _check_str(arg_name, str_val):
raise RuntimeError(f"Parameter '{arg_name}' should not be empty str")


def _check_int(arg_name, int_val, mininum=None, maximum=None):
def _check_int(arg_name, int_val, minimum=None, maximum=None):
"""Check whether the input parameters are reasonable int input"""
if not isinstance(int_val, int):
raise RuntimeError(f"Parameter '{arg_name}' should be int, but actually {type(int_val)}")
if mininum is not None and int_val < mininum:
if minimum is not None and int_val < minimum:
if maximum is not None:
raise RuntimeError(f"Parameter '{arg_name}' should be in range [{mininum},{maximum}]")
raise RuntimeError(f"Parameter '{arg_name}' should be >= {mininum}")
raise RuntimeError(f"Parameter '{arg_name}' should be in range [{minimum},{maximum}]")
raise RuntimeError(f"Parameter '{arg_name}' should be >= {minimum}")
if maximum is not None and int_val > maximum:
if mininum is not None:
raise RuntimeError(f"Parameter '{arg_name}' should be in range [{mininum},{maximum}]")
if minimum is not None:
raise RuntimeError(f"Parameter '{arg_name}' should be in range [{minimum},{maximum}]")
raise RuntimeError(f"Parameter '{arg_name}' should be <= {maximum}")


@@ -259,29 +259,6 @@ class Client:
print(status_code.value)
return ClientGrpcAsyncError({"error": "Grpc Error, " + str(status_code.value)})

def close(self):
"""
Used to release gRPC connection avoiding influence on the connection to the next restarted Serving server.

Examples:
>>> from mindspore_serving.client import Client
>>> import numpy as np
>>> instance = {"x1": np.ones((2, 2), np.int32), "x2": np.ones((2, 2), np.int32)}
>>> client = Client("localhost", 5500, "add", "add_cast")
>>> result = client.infer(instance)
>>> client.close()
>>> print(result)
"""
if self.stub:
del self.stub
self.stub = None

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
self.close()

def _create_request(self, instances):
"""Used to create request spec."""
if not isinstance(instances, (tuple, list)):
@@ -342,7 +319,7 @@ class Client:

class ClientGrpcAsyncResult:
"""
When Client.infer_async invoke sucessfully, a ClientGrpcAsyncResult object is returned.
When Client.infer_async invoke successfully, a ClientGrpcAsyncResult object is returned.

Examples:
>>> from mindspore_serving.client import Client


+ 5
- 5
mindspore_serving/log.py View File

@@ -91,7 +91,7 @@ class _MultiCompatibleRotatingFileHandler(RotatingFileHandler):
self.stream.close()
self.stream = None

# Attain an exclusive lock with bloking mode by `fcntl` module.
# Attain an exclusive lock with blocking mode by `fcntl` module.
with open(self.baseFilename, 'a') as file_pointer:
if platform.system() != "Windows":
fcntl.lockf(file_pointer.fileno(), fcntl.LOCK_EX)
@@ -396,7 +396,7 @@ def _clear_handler(logger):
logger.removeHandler(handler)


def _find_caller(stack_info=False):
def _find_caller(stack_info=False, _=1):
"""
Find the stack frame of the caller.

@@ -432,13 +432,13 @@ def _find_caller(stack_info=False):

def _get_stack_info(frame):
"""
Get the stack informations.
Get the stack information.

Args:
frame(frame): the frame requiring informations.
frame(frame): the frame requiring information.

Returns:
str, the string of the stack informations.
str, the string of the stack information.
"""
sinfo = None
stack_prefix = 'Stack (most recent call last):\n'


+ 0
- 1
mindspore_serving/master/__init__.py View File

@@ -14,7 +14,6 @@
# ============================================================================
"""MindSpore Serving Master"""

from mindspore_serving.worker import _check_version
from ._master import start_grpc_server, start_restful_server, start_master_server, stop

__all__ = []


+ 2
- 0
requirements_test.txt View File

@@ -1,2 +1,4 @@
numpy>=1.17.0
protobuf>=3.8.0
grpcio>=1.27.3
requests>=2.22.0

+ 4
- 13
tests/ut/CMakeLists.txt View File

@@ -3,11 +3,7 @@ add_library(protobuf::libprotobuf ALIAS protobuf::protobuf)
add_executable(protobuf::libprotoc ALIAS protobuf::protoc)

set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf)
if(CMAKE_CROSSCOMPILING)
find_program(_PROTOBUF_PROTOC protoc)
else()
set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)
endif()
set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)

# Find gRPC installation
# Looks for gRPCConfig.cmake file installed by gRPC's cmake installation.
@@ -24,13 +20,8 @@ message(STATUS "Using gRPC ${gRPC_VERSION}")
set(_GRPC_GRPCPP gRPC::grpc++)
set(_REFLECTION gRPC::grpc++_reflection)

if(CMAKE_CROSSCOMPILING)
find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin)
find_program(_GRPC_PYTHON_PLUGIN_EXECUTABLE grpc_python_plugin)
else()
set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)
set(_GRPC_PYTHON_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_python_plugin>)
endif()
set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)
set(_GRPC_PYTHON_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_python_plugin>)

# Proto file
# Generated sources
@@ -96,7 +87,7 @@ add_library(serving_ut_common STATIC ${UT_SERVING_COMMON})

target_link_libraries(serving_ut_common PRIVATE ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF})
target_link_libraries(serving_ut_common PRIVATE mindspore_serving::event mindspore_serving::event_pthreads)
target_link_libraries(serving_ut_common PRIVATE pthread mindspore::glog)
target_link_libraries(serving_ut_common PRIVATE pthread mindspore_serving::glog)
target_link_libraries(serving_ut_common PRIVATE ${SECUREC_LIBRARY})

# copy libevent lib


+ 5
- 2
tests/ut/cpp/runtest.sh View File

@@ -14,9 +14,12 @@
# limitations under the License.
# ============================================================================
set -e
BASEPATH=$(cd "$(dirname "$0")"; pwd)
BASEPATH=$(
cd "$(dirname "$0")"
pwd
)
PROJECT_PATH=${BASEPATH}/../../..
if [ $BUILD_PATH ];then
if [ $BUILD_PATH ]; then
echo "BUILD_PATH = $BUILD_PATH"
else
BUILD_PATH=${PROJECT_PATH}/build


+ 13
- 2
tests/ut/cpp/tests/parse_restful.cc View File

@@ -859,15 +859,26 @@ TEST_F(TestParseReply, test_reply_SUCCESS) {
std::cout << "===start====" << std::endl;
for (auto &it : element.items()) {
if (it.key() == "key_int") {
ASSERT_EQ(it.value(), 1);
ASSERT_TRUE(it.value().is_array());
ASSERT_EQ(it.value().size(), 1);
auto array_items = it.value().items();
auto int_val = *(array_items.begin());
ASSERT_TRUE(int_val.value().is_number_integer());
ASSERT_EQ(int_val.value(), 1);
count++;
} else if (it.key() == "key_bool") {
ASSERT_TRUE(it.value().is_boolean());
ASSERT_EQ(it.value(), false);
count++;
} else if (it.key() == "key_float") {
ASSERT_FLOAT_EQ(it.value(), 2.3);
ASSERT_TRUE(it.value().is_array());
ASSERT_EQ(it.value().size(), 1);
auto array_items = it.value().items();
auto float_val = *(array_items.begin());
ASSERT_FLOAT_EQ(float_val.value(), 2.3);
count++;
} else if (it.key() == "key_str") {
ASSERT_TRUE(it.value().is_string());
ASSERT_EQ(it.value(), "ut_test");
count++;
} else if (it.key() == "key_bytes") {


+ 4
- 2
tests/ut/python/runtest.sh View File

@@ -44,10 +44,12 @@ echo "LD_LIBRARY_PATH=LD_LIBRARY_PATH"
unset http_proxy
unset https_proxy

cd -
cd ${PROJECT_PATH}/tests/ut/python/tests/
if [ $# -gt 0 ]; then
pytest -v ${PROJECT_PATH}/tests/ut/python/tests/ -k $1
pytest -v . -k "$1"
else
pytest -v ${PROJECT_PATH}/tests/ut/python/tests
pytest -v .
fi

RET=$?


+ 38
- 0
tests/ut/python/tests/common.py View File

@@ -79,5 +79,43 @@ def serving_test(func):
finally:
master.stop()
worker.stop()
servable_dir = os.path.join(os.getcwd(), "serving_python_ut_servables")
rmtree(servable_dir, True)

return wrap_test


def release_client(client):
del client.stub
client.stub = None


# test servable_config.py with client
servable_config_import = r"""
import numpy as np
from mindspore_serving.worker import register
"""

servable_config_declare_servable = r"""
register.declare_servable(servable_file="tensor_add.mindir", model_format="MindIR", with_batch_dim=False)
"""

servable_config_preprocess_cast = r"""
def add_trans_datatype(x1, x2):
return x1.astype(np.float32), x2.astype(np.float32)
"""

servable_config_method_add_common = r"""
@register.register_method(output_names=["y"])
def add_common(x1, x2): # only support float32 inputs
y = register.call_servable(x1, x2)
return y
"""

servable_config_method_add_cast = r"""
@register.register_method(output_names=["y"])
def add_cast(x1, x2):
x1, x2 = register.call_preprocess(add_trans_datatype, x1, x2) # cast input to float32
y = register.call_servable(x1, x2)
return y
"""

+ 75
- 0
tests/ut/python/tests/common_restful.py View File

@@ -0,0 +1,75 @@
# Copyright 2020 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""test Serving, Common"""

import json
import requests
import numpy as np


def compare_float_value(expect, result):
expect = np.array(expect)
result = np.array(result)
assert (np.abs(expect - result) < 0.001).all()


def create_multi_instances_fp32(instance_count):
instances = []
# instance 1
y_data_list = []
for i in range(instance_count):
x1 = np.asarray([[1.1, 2.2], [3.3, 4.4]]).astype(np.float32) * (i + 1)
x2 = np.asarray([[5.5, 6.6], [7.7, 8.8]]).astype(np.float32) * (i + 1)
y_data_list.append(x1 + x2)
instances.append({"x1": x1.tolist(), "x2": x2.tolist()})
return instances, y_data_list


def create_multi_instances_int32_input_fp32_output(instance_count):
instances = []
# instance 1
y_data_list = []
for i in range(instance_count):
x1 = np.asarray([[1.1, 2.2], [3.3, 4.4]]).astype(np.int32) * (i + 1)
x2 = np.asarray([[5.5, 6.6], [7.7, 8.8]]).astype(np.int32) * (i + 1)
y_data_list.append((x1 + x2).astype(np.float32))
instances.append({"x1": x1.tolist(), "x2": x2.tolist()})
return instances, y_data_list


def check_result(result, y_data_list, output_name="y"):
result = result["instances"]
assert len(result) == len(y_data_list)
for result_item, expected_item in zip(result, y_data_list):
result_item = np.array(result_item[output_name])
print("result", result_item)
print("expect:", expected_item)
assert result_item.shape == expected_item.shape
assert (np.abs(result_item - expected_item) < 0.001).all()


def post_restful(ip, restful_port, servable_name, method_name, json_instances, version_number=None):
instances_map = {"instances": json_instances}
post_payload = json.dumps(instances_map)
print("request:", post_payload)
if version_number is not None:
request_url = f"http://{ip}:{restful_port}/model/{servable_name}/version/{version_number}:{method_name}"
result = requests.post(request_url, data=post_payload)
else:
request_url = f"http://{ip}:{restful_port}/model/{servable_name}:{method_name}"
result = requests.post(request_url, data=post_payload)
print("result", result.text)
result = json.loads(result.text)
return result

+ 98
- 78
tests/ut/python/tests/test_mater_worker_client.py View File

@@ -18,7 +18,9 @@ import numpy as np
from mindspore_serving import master
from mindspore_serving import worker
from mindspore_serving.client import Client
from common import ServingTestBase, serving_test
from common import ServingTestBase, serving_test, release_client
from common import servable_config_import, servable_config_declare_servable, servable_config_preprocess_cast
from common import servable_config_method_add_common, servable_config_method_add_cast


def create_multi_instances_fp32(instance_count):
@@ -50,7 +52,7 @@ def test_master_worker_client_success():
instance_count = 3
instances, y_data_list = create_multi_instances_fp32(instance_count)
result = client.infer(instances)
client.close() # avoid affecting the next use case
release_client(client)

print(result)
check_result(result, y_data_list)
@@ -63,11 +65,12 @@ def test_master_worker_client_multi_times_success():
worker.start_servable_in_master(base.servable_dir, base.servable_name, 0)
master.start_grpc_server("0.0.0.0", 5500)
# Client, use with avoid affecting the next use case
with Client("localhost", 5500, base.servable_name, "add_common") as client:
for instance_count in range(1, 5):
instances, y_data_list = create_multi_instances_fp32(instance_count)
result = client.infer(instances)
check_result(result, y_data_list)
client = Client("localhost", 5500, base.servable_name, "add_common")
for instance_count in range(1, 5):
instances, y_data_list = create_multi_instances_fp32(instance_count)
result = client.infer(instances)
check_result(result, y_data_list)
release_client(client)


@serving_test
@@ -78,10 +81,11 @@ def test_master_worker_client_alone_success():
master.start_grpc_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client
with Client("localhost", 5500, base.servable_name, "add_common") as client:
instance_count = 3
instances, y_data_list = create_multi_instances_fp32(instance_count)
result = client.infer(instances)
client = Client("localhost", 5500, base.servable_name, "add_common")
instance_count = 3
instances, y_data_list = create_multi_instances_fp32(instance_count)
result = client.infer(instances)
release_client(client)
check_result(result, y_data_list)


@@ -93,11 +97,12 @@ def test_master_worker_client_alone_multi_times_success():
master.start_grpc_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client, use with avoid affecting the next use case
with Client("localhost", 5500, base.servable_name, "add_common") as client:
for instance_count in range(1, 5):
instances, y_data_list = create_multi_instances_fp32(instance_count)
result = client.infer(instances)
check_result(result, y_data_list)
client = Client("localhost", 5500, base.servable_name, "add_common")
for instance_count in range(1, 5):
instances, y_data_list = create_multi_instances_fp32(instance_count)
result = client.infer(instances)
check_result(result, y_data_list)
release_client(client)


@serving_test
@@ -112,7 +117,7 @@ def test_master_worker_client_async_success():
instances, y_data_list = create_multi_instances_fp32(instance_count)
result_future = client.infer_async(instances)
result = result_future.result()
client.close() # avoid affecting the next use case
release_client(client) # avoid affecting the next use case

print(result)
check_result(result, y_data_list)
@@ -125,12 +130,13 @@ def test_master_worker_client_async_multi_times_success():
worker.start_servable_in_master(base.servable_dir, base.servable_name, 0)
master.start_grpc_server("0.0.0.0", 5500)
# Client, use with avoid affecting the next use case
with Client("localhost", 5500, base.servable_name, "add_common") as client:
for instance_count in range(1, 5):
instances, y_data_list = create_multi_instances_fp32(instance_count)
result_future = client.infer_async(instances)
result = result_future.result()
check_result(result, y_data_list)
client = Client("localhost", 5500, base.servable_name, "add_common")
for instance_count in range(1, 5):
instances, y_data_list = create_multi_instances_fp32(instance_count)
result_future = client.infer_async(instances)
result = result_future.result()
check_result(result, y_data_list)
release_client(client)


@serving_test
@@ -231,7 +237,7 @@ def test_master_worker_client_alone_repeat_grpc_and_restful_port_failed():
master.start_restful_server("0.0.0.0", 7600)
assert False
except RuntimeError as e:
assert "Serving Error: RESTful server start failed, create http listener faild, port" in str(e)
assert "Serving Error: RESTful server start failed, create http listener failed, port" in str(e)


@serving_test
@@ -246,37 +252,6 @@ def test_master_worker_client_alone_repeat_grpc_and_restful_port2_failed():
assert "Serving Error: Serving gRPC server start failed, create server failed, address" in str(e)


# test servable_config.py with client
servable_config_import = r"""
import numpy as np
from mindspore_serving.worker import register
"""

servable_config_declare_servable = r"""
register.declare_servable(servable_file="tensor_add.mindir", model_format="MindIR", with_batch_dim=False)
"""

servable_config_preprocess_cast = r"""
def add_trans_datatype(x1, x2):
return x1.astype(np.float32), x2.astype(np.float32)
"""

servable_config_method_add_common = r"""
@register.register_method(output_names=["y"])
def add_common(x1, x2): # only support float32 inputs
y = register.call_servable(x1, x2)
return y
"""

servable_config_method_add_cast = r"""
@register.register_method(output_names=["y"])
def add_cast(x1, x2):
x1, x2 = register.call_preprocess(add_trans_datatype, x1, x2) # cast input to float32
y = register.call_servable(x1, x2)
return y
"""


@serving_test
def test_master_worker_client_servable_content_success():
base = ServingTestBase()
@@ -292,8 +267,9 @@ def test_master_worker_client_servable_content_success():
# Client
instance_count = 3
instances, y_data_list = create_multi_instances_fp32(instance_count)
with Client("localhost", 5500, base.servable_name, "add_common") as client:
result = client.infer(instances)
client = Client("localhost", 5500, base.servable_name, "add_common")
result = client.infer(instances)
release_client(client)

print(result)
check_result(result, y_data_list)
@@ -320,9 +296,9 @@ def add_cast(x1, x2):
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
# Client, use with avoid affecting the next use case
with Client("localhost", 5500, base.servable_name, "add_cast") as client:
result = client.infer(instances)
client = Client("localhost", 5500, base.servable_name, "add_cast")
result = client.infer(instances)
release_client(client)

print(result)
assert "Preprocess Failed" in str(result[0]["error"])
@@ -349,9 +325,9 @@ def add_cast(x1, x2):
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
# Client, use with avoid affecting the next use case
with Client("localhost", 5500, base.servable_name, "add_cast") as client:
result = client.infer(instances)
client = Client("localhost", 5500, base.servable_name, "add_cast")
result = client.infer(instances)
release_client(client)

print(result)
assert "Postprocess Failed" in str(result[0]["error"])
@@ -387,9 +363,9 @@ def add_cast(x1, x2, label):
for i, instance in enumerate(instances):
instance["label"] = list_str[i]

# Client, use with avoid affecting the next use case
with Client("localhost", 5500, base.servable_name, "add_cast") as client:
result = client.infer(instances)
client = Client("localhost", 5500, base.servable_name, "add_cast")
result = client.infer(instances)
release_client(client)
assert result[0]["text"] == "ABC123"
assert result[1]["text"] == "DEF456"
assert result[2]["text"] == "HIJ789"
@@ -426,9 +402,9 @@ def add_cast(x1, x2, label):
for i, instance in enumerate(instances):
instance["label"] = str.encode(list_str[i])

# Client, use with avoid affecting the next use case
with Client("localhost", 5500, base.servable_name, "add_cast") as client:
result = client.infer(instances)
client = Client("localhost", 5500, base.servable_name, "add_cast")
result = client.infer(instances)
release_client(client)
assert bytes.decode(result[0]["text"]) == "ABC123"
assert bytes.decode(result[1]["text"]) == "DEF456"
assert bytes.decode(result[2]["text"]) == "HIJ789"
@@ -458,9 +434,9 @@ def add_cast(x1, x2, bool_val):
for i, instance in enumerate(instances):
instance["bool_val"] = (i % 2 == 0)

# Client, use with avoid affecting the next use case
with Client("localhost", 5500, base.servable_name, "add_cast") as client:
result = client.infer(instances)
client = Client("localhost", 5500, base.servable_name, "add_cast")
result = client.infer(instances)
release_client(client)
assert not result[0]["value"]
assert result[1]["value"]
assert not result[2]["value"]
@@ -490,9 +466,9 @@ def add_cast(x1, x2, int_val):
for i, instance in enumerate(instances):
instance["int_val"] = i * 2

# Client, use with avoid affecting the next use case
with Client("localhost", 5500, base.servable_name, "add_cast") as client:
result = client.infer(instances)
client = Client("localhost", 5500, base.servable_name, "add_cast")
result = client.infer(instances)
release_client(client)
assert result[0]["value"] == 1
assert result[1]["value"] == 3
assert result[2]["value"] == 5
@@ -522,9 +498,53 @@ def add_cast(x1, x2, float_val):
for i, instance in enumerate(instances):
instance["float_val"] = i * 2.2

# Client, use with avoid affecting the next use case
with Client("localhost", 5500, base.servable_name, "add_cast") as client:
result = client.infer(instances)
client = Client("localhost", 5500, base.servable_name, "add_cast")
result = client.infer(instances)
release_client(client)
assert result[0]["value"] == 1
assert result[1]["value"] == (2.2 + 1)
assert result[2]["value"] == (4.4 + 1)


@serving_test
def test_master_worker_client_preprocess_update_numpy_success():
base = ServingTestBase()
servable_content = servable_config_import
servable_content += servable_config_declare_servable
servable_content += r"""
def preprocess(x3):
x3[0] = 123
return x3
def postprocess(x3, x4):
return x3 + 1, x4 + 2

@register.register_method(output_names=["x3", "x4"])
def add_cast(x1, x2, x3):
x4 = register.call_preprocess(preprocess, x3) # [123, 1, 1], expect x3 is x4, same as python function call
y = register.call_servable(x1, x2)
x3, x4 = register.call_postprocess(postprocess, x3, x4)
return x3, x4
"""
base.init_servable_with_servable_config(1, servable_content)
worker.start_servable_in_master(base.servable_dir, base.servable_name)
master.start_grpc_server("0.0.0.0", 5500)
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
for instance in instances:
instance["x3"] = np.ones([3])

# Client, use with avoid affecting the next use case
client = Client("localhost", 5500, base.servable_name, "add_cast")
result = client.infer(instances)
release_client(client)
x3 = np.array([123, 1, 1]) + 1
x4 = np.array([123, 1, 1]) + 2

assert (result[0]["x3"] == x3).all()
assert (result[1]["x3"] == x3).all()
assert (result[2]["x3"] == x3).all()
assert (result[0]["x4"] == x4).all()
assert (result[1]["x4"] == x4).all()
assert (result[2]["x4"] == x4).all()

+ 949
- 0
tests/ut/python/tests/test_restful_base64_data.py View File

@@ -0,0 +1,949 @@
# Copyright 2020 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""test Serving RESTful, with master, worker and client"""

import base64
import numpy as np

from common import ServingTestBase, serving_test
from common import servable_config_import, servable_config_declare_servable
from common_restful import create_multi_instances_fp32, check_result, post_restful
from mindspore_serving import master
from mindspore_serving import worker


def start_str_restful_server():
base = ServingTestBase()
servable_content = servable_config_import
servable_content += servable_config_declare_servable
servable_content += r"""
index = 0
list_str = ["123", "456", "789"]
def postprocess(y, label):
global index
text = list_str[index]
index = (index + 1) if index + 1 < len(list_str) else 0
return y.astype(np.int32), label + text

@register.register_method(output_names=["y", "text"])
def add_common(x1, x2, label):
y = register.call_servable(x1, x2)
y, text = register.call_postprocess(postprocess, y, label)
return y, text
def empty_postprocess(y, label):
global index
if len(label) == 0:
text = list_str[index]
else:
text = ""
index = (index + 1) if index + 1 < len(list_str) else 0
return y.astype(np.int32), text

@register.register_method(output_names=["y", "text"])
def add_empty(x1, x2, label):
y = register.call_servable(x1, x2)
y, text = register.call_postprocess(empty_postprocess, y, label)
return y, text
"""
base.init_servable_with_servable_config(1, servable_content)
worker.start_servable_in_master(base.servable_dir, base.servable_name)
master.start_restful_server("0.0.0.0", 5500)
return base


def start_bytes_restful_server():
base = ServingTestBase()
servable_content = servable_config_import
servable_content += servable_config_declare_servable
servable_content += r"""
index = 0
list_str = ["123", "456", "789"]
def postprocess(y, label):
global index
label = bytes.decode(label.tobytes()) # bytes decode to str
text = list_str[index]
index = (index + 1) if index + 1 < len(list_str) else 0
return y.astype(np.int32), str.encode(label + text) # str encode to bytes

@register.register_method(output_names=["y", "text"])
def add_common(x1, x2, label):
y = register.call_servable(x1, x2)
y, text = register.call_postprocess(postprocess, y, label)
return y, text

def empty_postprocess(y, label):
global index
label = bytes.decode(label.tobytes()) # bytes decode to str
if len(label) == 0:
text = list_str[index]
else:
text = ""
index = (index + 1) if index + 1 < len(list_str) else 0
return y.astype(np.int32), str.encode(text) # str encode to bytes

@register.register_method(output_names=["y", "text"])
def add_empty(x1, x2, label):
y = register.call_servable(x1, x2)
y, text = register.call_postprocess(empty_postprocess, y, label)
return y, text
"""
base.init_servable_with_servable_config(1, servable_content)
worker.start_servable_in_master(base.servable_dir, base.servable_name)
master.start_restful_server("0.0.0.0", 5500)
return base


def start_bool_int_float_restful_server():
base = ServingTestBase()
servable_content = servable_config_import
servable_content += servable_config_declare_servable
servable_content += r"""
def bool_postprocess(y, bool_val):
return y.astype(np.int32), ~bool_val

@register.register_method(output_names=["y", "value"])
def add_bool(x1, x2, bool_val):
y = register.call_servable(x1, x2)
y, value = register.call_postprocess(bool_postprocess, y, bool_val)
return y, value

def int_postprocess(y, int_val):
return y.astype(np.int32), int_val + 1

@register.register_method(output_names=["y", "value"])
def add_int(x1, x2, int_val):
y = register.call_servable(x1, x2)
y, value = register.call_postprocess(int_postprocess, y, int_val)
return y, value
def float_postprocess(y, float_val):
value = float_val + 1
if value.dtype == np.float16:
value = value.astype(np.float32)
return y, value
@register.register_method(output_names=["y", "value"])
def add_float(x1, x2, float_val):
y = register.call_servable(x1, x2)
y, value = register.call_postprocess(float_postprocess, y, float_val)
return y, value
"""
base.init_servable_with_servable_config(1, servable_content)
worker.start_servable_in_master(base.servable_dir, base.servable_name)
master.start_restful_server("0.0.0.0", 5500)
return base


def common_test_restful_base64_str_scalar_input_output_success(shape):
base = start_str_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
list_str = ["ABC", "DEF", "HIJ"]
for i, instance in enumerate(instances):
if shape is None:
instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode(), "type": "str"}
else:
instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode(), "type": "str",
'shape': shape}

result = post_restful("localhost", 5500, base.servable_name, "add_common", instances)
result = result["instances"]
assert result[0]["text"] == "ABC123"
assert result[1]["text"] == "DEF456"
assert result[2]["text"] == "HIJ789"


@serving_test
def test_restful_base64_str_scalar_input_output_success():
common_test_restful_base64_str_scalar_input_output_success(shape=None)


@serving_test
def test_restful_base64_str_scalar_shape1_input_output_success():
common_test_restful_base64_str_scalar_input_output_success(shape=[1])


@serving_test
def test_restful_base64_str_scalar_shape_empty_input_output_success():
common_test_restful_base64_str_scalar_input_output_success(shape=[])


@serving_test
def test_restful_base64_empty_str_input_output_success():
base = start_str_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
list_str = ["ABC", "", "HIJ"]
for i, instance in enumerate(instances):
instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode(), "type": "str"}

result = post_restful("localhost", 5500, base.servable_name, "add_empty", instances)
result = result["instances"]
assert result[0]["text"] == ""
assert result[1]["text"] == "456"
assert result[2]["text"] == ""


@serving_test
def test_restful_base64_str_scalar_invalid_shape0_input_failed():
base = start_str_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
list_str = ["ABC", "DEF", "HIJ"]
for i, instance in enumerate(instances):
instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode(), "type": "str", "shape": [0]}

result = post_restful("localhost", 5500, base.servable_name, "add_common", instances)
assert "only support scalar when data type is string or bytes, please check 'type' or 'shape'" \
in str(result["error_msg"])


@serving_test
def test_restful_base64_str_scalar_invalid_shape_input_failed():
base = start_str_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
list_str = ["ABC", "DEF", "HIJ"]
for i, instance in enumerate(instances):
instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode(), "type": "str", 'shape': [2]}

result = post_restful("localhost", 5500, base.servable_name, "add_common", instances)
assert "json object, only support scalar when data type is string or bytes, please check 'type' or 'shape'" \
in str(result["error_msg"])


@serving_test
def test_restful_base64_str_1d_array_failed():
base = start_str_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
list_str = ["ABC", "DEF", "HIJ"]
for i, instance in enumerate(instances):
instance["label"] = [{"b64": base64.b64encode(str.encode(list_str[i])).decode(), "type": "str"},
{"b64": base64.b64encode(str.encode(list_str[i])).decode(), "type": "str"}]

result = post_restful("localhost", 5500, base.servable_name, "add_cast", instances)
assert "json array, string or bytes type only support one item" in str(result["error_msg"])


def common_test_restful_bytes_input_output_success(shape):
base = start_bytes_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
list_str = ["ABC", "DEF", "HIJ"]
for i, instance in enumerate(instances):
if shape is not None:
instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode(), "shape": shape}
else:
instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode()}

result = post_restful("localhost", 5500, base.servable_name, "add_common", instances)
result = result["instances"]
b64_decode_to_str = lambda a: bytes.decode(base64.b64decode(a["b64"]))
assert b64_decode_to_str(result[0]["text"]) == "ABC123"
assert b64_decode_to_str(result[1]["text"]) == "DEF456"
assert b64_decode_to_str(result[2]["text"]) == "HIJ789"


@serving_test
def test_restful_bytes_input_output_success():
common_test_restful_bytes_input_output_success(None)


@serving_test
def test_restful_bytes_empty_shape_success():
common_test_restful_bytes_input_output_success([])


@serving_test
def test_restful_bytes_shape1_success():
common_test_restful_bytes_input_output_success([1])


@serving_test
def test_restful_empty_bytes_input_output_success():
base = start_bytes_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
list_str = ["ABC", "", "HIJ"]
for i, instance in enumerate(instances):
instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode()}

result = post_restful("localhost", 5500, base.servable_name, "add_empty", instances)
result = result["instances"]
b64_decode_to_str = lambda a: bytes.decode(base64.b64decode(a["b64"]))
assert b64_decode_to_str(result[0]["text"]) == ""
assert b64_decode_to_str(result[1]["text"]) == "456"
assert b64_decode_to_str(result[2]["text"]) == ""


@serving_test
def test_restful_bytes_1d_array_failed():
base = start_bytes_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
list_str = ["ABC", "DEF", "HIJ"]
for i, instance in enumerate(instances):
instance["label"] = [{"b64": base64.b64encode(str.encode(list_str[i])).decode()},
{"b64": base64.b64encode(str.encode(list_str[i])).decode()}]

result = post_restful("localhost", 5500, base.servable_name, "add_cast", instances)
assert "json array, string or bytes type only support one item" in str(result["error_msg"])


@serving_test
def test_restful_bytes_invalid_shape_input_failed():
base = start_bytes_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
list_str = ["ABC", "DEF", "HIJ"]
for i, instance in enumerate(instances):
instance["label"] = {"b64": base64.b64encode(str.encode(list_str[i])).decode(), 'shape': [0]}

result = post_restful("localhost", 5500, base.servable_name, "add_cast", instances)
assert "only support scalar when data type is string or bytes, please check 'type' or 'shape'" \
in result["error_msg"]


@serving_test
def test_restful_base64_bool_scalar_input_output_success():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
for i, instance in enumerate(instances):
val = np.int8(i % 2 == 0)
instance["bool_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "bool"}

result = post_restful("localhost", 5500, base.servable_name, "add_bool", instances)
result = result["instances"]
assert not result[0]["value"]
assert result[1]["value"]
assert not result[2]["value"]


@serving_test
def test_restful_base64_bool_1d_array_input_output_success():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
for i, instance in enumerate(instances):
val = [(i % 2 == 0)] * (i + 1)
val = np.array(val)
instance["bool_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "bool", "shape": [i + 1]}

result = post_restful("localhost", 5500, base.servable_name, "add_bool", instances)
result = result["instances"]
assert result[0]["value"] == [False]
assert result[1]["value"] == [True, True]
assert result[2]["value"] == [False, False, False]


@serving_test
def test_restful_base64_bool_2d_array_input_output_success():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
for i, instance in enumerate(instances):
val = (i % 2 == 0)
val = [[val] * (i + 1)] * (i + 1)
val = np.array(val)
instance["bool_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "bool",
"shape": [i + 1, i + 1]}

result = post_restful("localhost", 5500, base.servable_name, "add_bool", instances)
result = result["instances"]
assert result[0]["value"] == [[False]]
assert result[1]["value"] == [[True, True], [True, True]]
assert result[2]["value"] == [[False, False, False], [False, False, False], [False, False, False]]


@serving_test
def test_restful_base64_int_scalar_input_output_success():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
for i, instance in enumerate(instances):
val = np.int32(i * 2)
instance["int_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "int32"}

result = post_restful("localhost", 5500, base.servable_name, "add_int", instances)
result = result["instances"]
assert result[0]["value"] == 1
assert result[1]["value"] == 3
assert result[2]["value"] == 5


@serving_test
def test_restful_base64_int_1d_empty_input_output_success():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
for i, instance in enumerate(instances):
if i % 2 == 0:
val = []
else:
val = [i * 2] * (i + 1)
val = np.array(val).astype(np.int32)
instance["int_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "int32", "shape": val.shape}

result = post_restful("localhost", 5500, base.servable_name, "add_int", instances)
result = result["instances"]
assert result[0]["value"] == []
assert result[1]["value"] == [3, 3]
assert result[2]["value"] == []


@serving_test
def test_restful_base64_int_2d_empty_input_output_success():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
for i, instance in enumerate(instances):
if i % 2 == 0:
val = [[]]
else:
val = [i * 2] * (i + 1)
val = np.array(val).astype(np.int32)
instance["int_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "int32", "shape": val.shape}

result = post_restful("localhost", 5500, base.servable_name, "add_int", instances)
result = result["instances"]
assert result[0]["value"] == [[]]
assert result[1]["value"] == [3, 3]
assert result[2]["value"] == [[]]


@serving_test
def test_restful_base64_int_2d_empty_invalid_shape_failed():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
for _, instance in enumerate(instances):
val = [[]]
val = np.array(val).astype(np.int32)
instance["int_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "int32", "shape": [1, 2, 0, 1]}

result = post_restful("localhost", 5500, base.servable_name, "add_int", instances)
assert "json object, key is 'shape', invalid shape value" in result["error_msg"]


@serving_test
def test_restful_base64_int_1d_array_input_output_success():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
for i, instance in enumerate(instances):
val = i * 2
val = [val] * (i + 1)
val = np.array(val).astype(np.int32)
instance["int_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "int32", "shape": val.shape}

result = post_restful("localhost", 5500, base.servable_name, "add_int", instances)
result = result["instances"]
assert result[0]["value"] == [1]
assert result[1]["value"] == [3, 3]
assert result[2]["value"] == [5, 5, 5]


def common_test_restful_base64_int_type_2d_array_input_output_success(dtype):
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
dtype_str_map = {np.int8: "int8", np.int16: "int16", np.int32: "int32", np.int64: "int64"}
assert dtype in dtype_str_map
for i, instance in enumerate(instances):
val = (i + 1) * 2 * (-1 if i % 2 == 0 else 1) # -2, 4, -6
val = [[val] * (i + 1)] * (i + 1)
val = np.array(val).astype(dtype)
instance["int_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': dtype_str_map[dtype],
"shape": val.shape}

result = post_restful("localhost", 5500, base.servable_name, "add_int", instances)
result = result["instances"]
assert result[0]["value"] == [[-1]]
assert result[1]["value"] == [[5, 5], [5, 5]]
assert result[2]["value"] == [[-5, -5, -5], [-5, -5, -5], [-5, -5, -5]]


@serving_test
def test_restful_base64_int8_2d_array_input_output_success():
common_test_restful_base64_int_type_2d_array_input_output_success(np.int8)


@serving_test
def test_restful_base64_int16_2d_array_input_output_success():
common_test_restful_base64_int_type_2d_array_input_output_success(np.int16)


@serving_test
def test_restful_base64_int32_2d_array_input_output_success():
common_test_restful_base64_int_type_2d_array_input_output_success(np.int32)


@serving_test
def test_restful_base64_int64_2d_array_input_output_success():
common_test_restful_base64_int_type_2d_array_input_output_success(np.int64)


def common_test_restful_base64_uint_type_2d_array_input_output_success(dtype):
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
dtype_str_map = {np.uint8: "uint8", np.uint16: "uint16", np.uint32: "uint32", np.uint64: "uint64"}
assert dtype in dtype_str_map
for i, instance in enumerate(instances):
val = i * 2
val = [[val] * (i + 1)] * (i + 1)
val = np.array(val).astype(dtype)
instance["int_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': dtype_str_map[dtype],
"shape": val.shape}

result = post_restful("localhost", 5500, base.servable_name, "add_int", instances)
result = result["instances"]
assert result[0]["value"] == [[1]]
assert result[1]["value"] == [[3, 3], [3, 3]]
assert result[2]["value"] == [[5, 5, 5], [5, 5, 5], [5, 5, 5]]


@serving_test
def test_restful_base64_uint8_2d_array_input_output_success():
common_test_restful_base64_uint_type_2d_array_input_output_success(np.uint8)


@serving_test
def test_restful_base64_uint16_2d_array_input_output_success():
common_test_restful_base64_uint_type_2d_array_input_output_success(np.uint16)


@serving_test
def test_restful_base64_uint32_2d_array_input_output_success():
common_test_restful_base64_uint_type_2d_array_input_output_success(np.uint32)


@serving_test
def test_restful_base64_uint64_2d_array_input_output_success():
common_test_restful_base64_uint_type_2d_array_input_output_success(np.uint64)


@serving_test
def test_restful_base64_float_scalar_input_output_success():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
for i, instance in enumerate(instances):
val = np.float32(i * 2.2)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp32"}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
result = result["instances"]
assert result[0]["value"] == 1.0
assert abs(result[1]["value"] - (2.2 + 1)) < 0.001
assert abs(result[2]["value"] - (4.4 + 1)) < 0.001


@serving_test
def test_restful_base64_float_1d_array_input_output_success():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
y_data_list = []
for i, instance in enumerate(instances):
val = [i * 2.2 * (-1 if i % 2 == 0 else 1)] * (i + 1) # [0], [2.2, 2.2], [-4.4, -4.4, -4.4]
val = np.array(val).astype(np.float32)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp32", 'shape': [i + 1]}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
check_result(result, y_data_list, "value")


def common_test_restful_base64_float_type_2d_array_input_output_success(dtype):
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype_str_map = {np.float16: "fp16", np.float32: "fp32", np.float64: "fp64"}
assert dtype in dtype_str_map

y_data_list = []
for i, instance in enumerate(instances):
val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4
val = [[val] * (i + 1)] * (i + 1)
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': dtype_str_map[dtype],
'shape': [i + 1, i + 1]}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
check_result(result, y_data_list, "value")


@serving_test
def test_restful_base64_float16_2d_array_input_output_success():
common_test_restful_base64_float_type_2d_array_input_output_success(np.float16)


@serving_test
def test_restful_base64_float32_2d_array_input_output_success():
common_test_restful_base64_float_type_2d_array_input_output_success(np.float32)


@serving_test
def test_restful_base64_float64_2d_array_input_output_success():
common_test_restful_base64_float_type_2d_array_input_output_success(np.float64)


@serving_test
def test_restful_base64_float16_2d_array_not_support_fp16_output_failed():
base = ServingTestBase()
servable_content = servable_config_import
servable_content += servable_config_declare_servable
servable_content += r"""
def postprocess(y, float_val):
return y, float_val + 1

@register.register_method(output_names=["y", "value"])
def add_cast(x1, x2, float_val):
y = register.call_servable(x1, x2)
y, value = register.call_postprocess(postprocess, y, float_val)
return y, value
"""
base.init_servable_with_servable_config(1, servable_content)
worker.start_servable_in_master(base.servable_dir, base.servable_name)
master.start_restful_server("0.0.0.0", 5500)
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype = np.float16
dtype_str_map = {np.float16: "fp16", np.float32: "fp32", np.float64: "fp64"}
assert dtype in dtype_str_map

y_data_list = []
for i, instance in enumerate(instances):
val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4
val = [[val] * (i + 1)] * (i + 1)
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': dtype_str_map[dtype],
'shape': [i + 1, i + 1]}

result = post_restful("localhost", 5500, base.servable_name, "add_cast", instances)
assert "fp16 reply is not supported" in result["error_msg"]


@serving_test
def test_restful_base64_dtype_unknow_failed():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype = np.float16
dtype_str_map = {np.float16: "fp16", np.float32: "fp32", np.float64: "fp64"}
assert dtype in dtype_str_map

y_data_list = []
for i, instance in enumerate(instances):
val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4
val = [[val] * (i + 1)] * (i + 1)
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "dtype_unknow",
'shape': [i + 1, i + 1]}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
assert "Parser request failed, json object, specified type:'dtype_unknow' is illegal" in result["error_msg"]


@serving_test
def test_restful_base64_dtype_empty_failed():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype = np.float16
dtype_str_map = {np.float16: "fp16", np.float32: "fp32", np.float64: "fp64"}
assert dtype in dtype_str_map

y_data_list = []
for i, instance in enumerate(instances):
val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4
val = [[val] * (i + 1)] * (i + 1)
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "",
'shape': [i + 1, i + 1]}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
assert "Parser request failed, json object, specified type:'' is illegal" in result["error_msg"]


@serving_test
def test_restful_base64_float16_2d_array_shape_not_match1_large_failed():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype = np.float16
dtype_str_map = {np.float16: "fp16", np.float32: "fp32", np.float64: "fp64"}
assert dtype in dtype_str_map

y_data_list = []
for i, instance in enumerate(instances):
val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4
val = [[val] * (i + 1)] * (i + 1)
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': dtype_str_map[dtype],
'shape': [i + 2, i + 2]}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
assert "Parser request failed, size is not matched" in result["error_msg"]


@serving_test
def test_restful_base64_float16_2d_array_shape_not_match2_small_failed():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype = np.float16
dtype_str_map = {np.float16: "fp16", np.float32: "fp32", np.float64: "fp64"}
assert dtype in dtype_str_map

y_data_list = []
for i, instance in enumerate(instances):
val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4
val = [[val] * (i + 2)] * (i + 2)
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': dtype_str_map[dtype],
'shape': [i + 1, i + 1]}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
assert "Parser request failed, size is not matched" in result["error_msg"]


@serving_test
def test_restful_base64_float16_2d_array_shape_not_match3_small_failed():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype = np.float16
dtype_str_map = {np.float16: "fp16", np.float32: "fp32", np.float64: "fp64"}
assert dtype in dtype_str_map

y_data_list = []
for i, instance in enumerate(instances):
val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4
val = [[val] * (i + 2)] * (i + 2)
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': dtype_str_map[dtype],
'shape': [i + 2, i]}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
assert "Parser request failed, size is not matched" in result["error_msg"]


@serving_test
def test_restful_base64_float16_2d_array_dtype_not_match4_empty_data_failed():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype = np.float16
y_data_list = []
for i, instance in enumerate(instances):
val = [[]]
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp16",
'shape': [i + 1, i + 1]}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
assert "Parser request failed, size is not matched" in result["error_msg"]


@serving_test
def test_restful_base64_float16_2d_array_dtype_not_match5_empty_shape_failed():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype = np.float16
y_data_list = []
for i, instance in enumerate(instances):
val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4
val = [[val] * (i + 2)] * (i + 2)
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp16",
'shape': []}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
assert "Parser request failed, size is not matched" in result["error_msg"]


@serving_test
def test_restful_base64_float16_2d_array_dtype_not_match6_empty_shape3_failed():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype = np.float16
y_data_list = []
for i, instance in enumerate(instances):
val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4
val = [[val] * (i + 2)] * (i + 2)
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp16"}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
assert "Parser request failed, size is not matched" in result["error_msg"]


@serving_test
def test_restful_base64_float16_2d_array_dtype_not_match_failed():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype = np.float16
y_data_list = []
for i, instance in enumerate(instances):
val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4
val = [[val] * (i + 2)] * (i + 2)
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp32",
'shape': [i + 2, i + 2]}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
assert "Parser request failed, size is not matched" in result["error_msg"]


@serving_test
def test_restful_base64_float16_2d_array_invalid_shape_2d_shape_failed():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype = np.float16
y_data_list = []
for i, instance in enumerate(instances):
val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4
val = [[val] * (i + 2)] * (i + 2)
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp16", "shape": [[]]}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
assert "json object, key is 'shape', array value should be unsigned integer" in result["error_msg"]


@serving_test
def test_restful_base64_float16_2d_array_invalid_shape2_str_shape_failed():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype = np.float16
y_data_list = []
for i, instance in enumerate(instances):
val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4
val = [[val] * (i + 2)] * (i + 2)
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp16", "shape": ["abc"]}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
assert "json object, key is 'shape', array value should be unsigned integer" in result["error_msg"]


@serving_test
def test_restful_base64_float16_2d_array_invalid_shape3_float_shape_failed():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype = np.float16
y_data_list = []
for i, instance in enumerate(instances):
val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4
val = [[val] * (i + 2)] * (i + 2)
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp16", "shape": [1.1]}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
assert "json object, key is 'shape', array value should be unsigned integer" in result["error_msg"]


@serving_test
def test_restful_base64_float16_2d_array_invalid_shape4_negative_shape_failed():
base = start_bool_int_float_restful_server()
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

dtype = np.float16
y_data_list = []
for i, instance in enumerate(instances):
val = i * 2.2 * (-1 if i % 2 == 0 else 1) # 0, 2.2 ,-4.4
val = [[val] * (i + 2)] * (i + 2)
val = np.array(val).astype(dtype)
y_data_list.append(val + 1)
instance["float_val"] = {"b64": base64.b64encode(val.tobytes()).decode(), 'type': "fp16", "shape": [-1]}

result = post_restful("localhost", 5500, base.servable_name, "add_float", instances)
assert "json object, key is 'shape', array value should be unsigned integer" in result["error_msg"]

+ 1040
- 0
tests/ut/python/tests/test_restful_json_data.py
File diff suppressed because it is too large
View File


+ 335
- 0
tests/ut/python/tests/test_restful_request.py View File

@@ -0,0 +1,335 @@
# Copyright 2020 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""test Serving RESTful, with master, worker and client"""

import json
import requests
from mindspore_serving import master
from mindspore_serving import worker
from common import ServingTestBase, serving_test
from common import servable_config_import, servable_config_declare_servable
from common_restful import create_multi_instances_fp32, check_result, post_restful
from common_restful import create_multi_instances_int32_input_fp32_output


@serving_test
def test_restful_request_success():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
worker.start_servable_in_master(base.servable_dir, base.servable_name, 0)
master.start_restful_server("0.0.0.0", 5500)
# Client
instance_count = 3
instances, y_data_list = create_multi_instances_fp32(instance_count)
result = post_restful("localhost", 5500, base.servable_name, "add_common", instances)
check_result(result, y_data_list)


@serving_test
def test_restful_request_multi_times_success():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
worker.start_servable_in_master(base.servable_dir, base.servable_name, 0)
master.start_restful_server("0.0.0.0", 5500)
for instance_count in range(1, 5):
instances, y_data_list = create_multi_instances_fp32(instance_count)
result = post_restful("localhost", 5500, base.servable_name, "add_common", instances)
check_result(result, y_data_list)


@serving_test
def test_restful_request_multi_times_int32_success():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
worker.start_servable_in_master(base.servable_dir, base.servable_name, 0)
master.start_restful_server("0.0.0.0", 5500)
for instance_count in range(1, 5):
instances, y_data_list = create_multi_instances_int32_input_fp32_output(instance_count)
result = post_restful("localhost", 5500, base.servable_name, "add_cast", instances)
check_result(result, y_data_list)


@serving_test
def test_restful_request_worker_alone_success():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
master.start_master_server(master_port=7600)
master.start_restful_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client
instance_count = 3
instances, y_data_list = create_multi_instances_fp32(instance_count)
result = post_restful("localhost", 5500, base.servable_name, "add_common", instances)
check_result(result, y_data_list)


@serving_test
def test_restful_request_worker_alone_multi_times_success():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
master.start_master_server(master_port=7600)
master.start_restful_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client
for instance_count in range(1, 5):
instances, y_data_list = create_multi_instances_fp32(instance_count)
result = post_restful("localhost", 5500, base.servable_name, "add_common", instances)
check_result(result, y_data_list)


@serving_test
def test_restful_request_worker_alone_servable_invalid_failed():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
master.start_master_server(master_port=7600)
master.start_restful_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
result = post_restful("localhost", 5500, base.servable_name + "_error", "add_common", instances)
assert "servable is not available" in str(result["error_msg"])


@serving_test
def test_restful_request_worker_alone_method_invalid_failed():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
master.start_master_server(master_port=7600)
master.start_restful_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
result = post_restful("localhost", 5500, base.servable_name, "add_common" + "_error", instances)
assert "method is not available" in str(result["error_msg"])


@serving_test
def test_restful_request_worker_alone_with_version_number_0_success():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
master.start_master_server(master_port=7600)
master.start_restful_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client
instance_count = 3
instances, y_data_list = create_multi_instances_fp32(instance_count)
result = post_restful("localhost", 5500, base.servable_name, "add_common", instances, 0)
check_result(result, y_data_list)


@serving_test
def test_restful_request_worker_alone_with_version_number_1_success():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
master.start_master_server(master_port=7600)
master.start_restful_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client
instance_count = 3
instances, y_data_list = create_multi_instances_fp32(instance_count)
result = post_restful("localhost", 5500, base.servable_name, "add_common", instances, 1)
check_result(result, y_data_list)


@serving_test
def test_restful_request_worker_alone_with_version_number_2_invalid_failed():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
master.start_master_server(master_port=7600)
master.start_restful_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
result = post_restful("localhost", 5500, base.servable_name, "add_common", instances, 2)
assert "servable is not available" in str(result["error_msg"])


@serving_test
def test_restful_request_worker_alone_version_number_negative_failed():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
master.start_master_server(master_port=7600)
master.start_restful_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
result = post_restful("localhost", 5500, base.servable_name, "add_common", instances, -1)
assert "please check url, version number range failed" in str(result["error_msg"])


@serving_test
def test_restful_request_worker_alone_without_model_invalid_failed():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
master.start_master_server(master_port=7600)
master.start_restful_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

instances_map = {"instances": instances}
post_payload = json.dumps(instances_map)
print("request:", post_payload)
request_url = f"http://localhost:5500/x/:add_common"
result = requests.post(request_url, data=post_payload)
print("result", result.text)
result = json.loads(result.text)
assert "please check url, the keyword:[model] must contain" in str(result["error_msg"])


@serving_test
def test_restful_request_worker_alone_without_method_invalid_failed():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
master.start_master_server(master_port=7600)
master.start_restful_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

instances_map = {"instances": instances}
post_payload = json.dumps(instances_map)
print("request:", post_payload)
request_url = f"http://localhost:5500/model/{base.servable_name}"
result = requests.post(request_url, data=post_payload)
print("result", result.text)
result = json.loads(result.text)
assert "please check url, the keyword:[service method] must contain." in str(result["error_msg"])


@serving_test
def test_restful_request_without_method_invalid_failed():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
master.start_master_server(master_port=7600)
master.start_restful_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)

instances_map = {"instances": instances}
post_payload = json.dumps(instances_map)
print("request:", post_payload)
request_url = f"http://localhost:5500/model/{base.servable_name}"
result = requests.post(request_url, data=post_payload)
print("result", result.text)
result = json.loads(result.text)
assert "please check url, the keyword:[service method] must contain." in str(result["error_msg"])


@serving_test
def test_restful_request_worker_alone_servable_version_reverse_success():
base = ServingTestBase()
base.init_servable(1, "add_servable_config.py")
master.start_master_server(master_port=7600)
master.start_restful_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client
instance_count = 3
instances, y_data_list = create_multi_instances_fp32(instance_count)

instances_map = {"instances": instances}
post_payload = json.dumps(instances_map)
print("request:", post_payload)
request_url = f"http://localhost:5500/version/0/model/{base.servable_name}:add_common"
result = requests.post(request_url, data=post_payload)
print("result", result.text)
result = json.loads(result.text)
check_result(result, y_data_list)


@serving_test
def test_restful_request_preprocess_outputs_count_not_match_failed():
base = ServingTestBase()
servable_content = servable_config_import
servable_content += servable_config_declare_servable
servable_content += r"""
def add_trans_datatype(x1, x2):
return x1.astype(np.float32)

@register.register_method(output_names=["y"])
def add_cast(x1, x2):
x1, x2 = register.call_preprocess(add_trans_datatype, x1, x2) # cast input to float32
y = register.call_servable(x1, x2)
return y
"""
base.init_servable_with_servable_config(1, servable_content)
worker.start_servable_in_master(base.servable_dir, base.servable_name)
master.start_restful_server("0.0.0.0", 5500)
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
result = post_restful("localhost", 5500, base.servable_name, "add_cast", instances)

print(result)
assert "Preprocess Failed" in str(result["instances"][0]["error_msg"])


@serving_test
def test_restful_request_postprocess_outputs_count_not_match_failed():
base = ServingTestBase()
servable_content = servable_config_import
servable_content += servable_config_declare_servable
servable_content += r"""
def add_trans_datatype(x1, x2):
return x1.astype(np.float32)

@register.register_method(output_names=["y"])
def add_cast(x1, x2):
y = register.call_servable(x1, x2)
y, y2 = register.call_postprocess(add_trans_datatype, y, x2)
return y
"""
base.init_servable_with_servable_config(1, servable_content)
worker.start_servable_in_master(base.servable_dir, base.servable_name)
master.start_restful_server("0.0.0.0", 5500)
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
result = post_restful("localhost", 5500, base.servable_name, "add_cast", instances)
assert "Postprocess Failed" in str(result["instances"][0]["error_msg"])


@serving_test
def test_restful_request_worker_alone_outputs_count_not_match_failed():
base = ServingTestBase()
servable_content = servable_config_import
servable_content += servable_config_declare_servable
servable_content += r"""
def add_trans_datatype(x1, x2):
return x1.astype(np.float32)

@register.register_method(output_names=["y"])
def add_cast(x1, x2):
y = register.call_servable(x1, x2)
y, y2 = register.call_postprocess(add_trans_datatype, y, x2)
return y
"""
base.init_servable_with_servable_config(1, servable_content)
master.start_master_server(master_port=7600)
master.start_restful_server("0.0.0.0", 5500)
worker.start_servable(base.servable_dir, base.servable_name, master_port=7600, worker_port=6600)
# Client
instance_count = 3
instances, _ = create_multi_instances_fp32(instance_count)
result = post_restful("localhost", 5500, base.servable_name + "_error", "add_common", instances)
assert "servable is not available" in str(result["error_msg"])

Loading…
Cancel
Save