16 #include "tensorflow_serving/util/json_tensor.h"
21 #include "google/protobuf/message.h"
22 #include "google/protobuf/text_format.h"
23 #include "google/protobuf/util/message_differencer.h"
24 #include "rapidjson/document.h"
25 #include "rapidjson/error/en.h"
26 #include <gmock/gmock.h>
27 #include <gtest/gtest.h>
28 #include "absl/strings/substitute.h"
29 #include "tensorflow/core/lib/core/errors.h"
30 #include "tensorflow/core/lib/core/status_test_util.h"
31 #include "tensorflow/core/platform/protobuf.h"
32 #include "tensorflow_serving/apis/model.pb.h"
33 #include "tensorflow_serving/apis/predict.pb.h"
34 #include "tensorflow_serving/test_util/test_util.h"
36 namespace tensorflow {
40 using protobuf::TextFormat;
41 using protobuf::util::DefaultFieldComparator;
42 using protobuf::util::MessageDifferencer;
43 using test_util::EqualsProto;
44 using ::testing::HasSubstr;
46 using TensorInfoMap = ::google::protobuf::Map<string, TensorInfo>;
47 using TensorMap = ::google::protobuf::Map<string, TensorProto>;
49 std::function<tensorflow::Status(
const string&, TensorInfoMap*)> getmap(
50 const TensorInfoMap& map) {
51 return [&map](
const string&, TensorInfoMap* m) {
57 TEST(JsontensorTest, SingleUnnamedTensor) {
58 TensorInfoMap infomap;
60 TextFormat::ParseFromString(
"dtype: DT_INT32", &infomap[
"default"]));
63 JsonPredictRequestFormat format;
64 TF_EXPECT_OK(FillPredictRequestFromJson(R
"(
66 "instances": [[1,2],[3,4],[5,6]]
68 getmap(infomap), &req, &format));
69 auto tmap = req.inputs();
70 EXPECT_EQ(tmap.size(), 1);
71 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
72 EXPECT_THAT(tmap[
"default"], EqualsProto(R
"(
87 TEST(JsontensorTest, DeeplyNestedWellFormed) {
88 TensorInfoMap infomap;
90 TextFormat::ParseFromString("dtype: DT_INT32", &infomap[
"default"]));
93 JsonPredictRequestFormat format;
94 std::string json_req = R
"({"instances":[1], "nested":)";
95 json_req.append(500000, '[');
96 json_req.append(500000,
']');
99 FillPredictRequestFromJson(json_req, getmap(infomap), &req, &format));
100 auto tmap = req.inputs();
101 EXPECT_EQ(tmap.size(), 1);
104 TEST(JsontensorTest, DeeplyNestedMalformed) {
105 TensorInfoMap infomap;
107 TextFormat::ParseFromString(
"dtype: DT_INT32", &infomap[
"default"]));
110 JsonPredictRequestFormat format;
111 std::string json_req = R
"({"signature_name":)";
112 json_req.append(500000, '[');
113 json_req.append(500000,
']');
114 json_req.append(
"}");
116 FillPredictRequestFromJson(json_req, getmap(infomap), &req, &format);
117 ASSERT_TRUE(errors::IsInvalidArgument(status));
118 EXPECT_THAT(status.message(), HasSubstr(
"key must be a string value"));
121 TEST(JsontensorTest, MixedInputForFloatTensor) {
122 TensorInfoMap infomap;
124 TextFormat::ParseFromString(
"dtype: DT_FLOAT", &infomap[
"default"]));
127 JsonPredictRequestFormat format;
128 TF_EXPECT_OK(FillPredictRequestFromJson(R
"(
130 "instances": [1, 2.0, 3, 4, 5.003, 0.007, 0.0]
132 getmap(infomap), &req, &format));
133 auto tmap = req.inputs();
134 EXPECT_EQ(tmap.size(), 1);
135 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
136 EXPECT_THAT(tmap[
"default"], EqualsProto(R
"(
138 tensor_shape { dim { size: 7 } }
149 TEST(JsontensorTest, MixedInputForDoubleTensor) {
150 TensorInfoMap infomap;
152 TextFormat::ParseFromString("dtype: DT_DOUBLE", &infomap[
"default"]));
155 JsonPredictRequestFormat format;
156 TF_EXPECT_OK(FillPredictRequestFromJson(R
"(
158 "instances": [1.0, 2, 3, 4, 0.662, 0, 0.0]
160 getmap(infomap), &req, &format));
161 auto tmap = req.inputs();
162 EXPECT_EQ(tmap.size(), 1);
163 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
164 EXPECT_THAT(tmap[
"default"], EqualsProto(R
"(
166 tensor_shape { dim { size: 7 } }
183 TEST(JsontensorTest, FloatTensorWithPrecisionLoss) {
184 TensorInfoMap infomap;
186 TextFormat::ParseFromString(
"dtype: DT_FLOAT", &infomap[
"default"]));
189 JsonPredictRequestFormat format;
190 TF_EXPECT_OK(FillPredictRequestFromJson(R
"(
192 "instances": [1435774380]
194 getmap(infomap), &req, &format));
195 auto tmap = req.inputs();
196 EXPECT_EQ(tmap.size(), 1);
197 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
200 EXPECT_THAT(tmap[
"default"], EqualsProto(R
"(
202 tensor_shape { dim { size: 1 } }
203 float_val: 1435774380
207 TF_EXPECT_OK(FillPredictRequestFromJson(R
"(
209 "instances": [1435774380.0]
211 getmap(infomap), &req, &format));
213 EXPECT_EQ(tmap.size(), 1);
214 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
217 EXPECT_THAT(tmap[
"default"], EqualsProto(R
"(
219 tensor_shape { dim { size: 1 } }
220 float_val: 1435774380.0
224 TEST(JsontensorTest, FloatTensorThatExceedsMaxReturnsInf) {
225 TensorInfoMap infomap;
227 TextFormat::ParseFromString("dtype: DT_FLOAT", &infomap[
"default"]));
230 JsonPredictRequestFormat format;
231 TF_EXPECT_OK(FillPredictRequestFromJson(
232 absl::Substitute(R
"({ "instances": [$0] })",
233 std::numeric_limits<double>::max()),
234 getmap(infomap), &req, &format));
235 auto tmap = req.inputs();
236 EXPECT_EQ(tmap.size(), 1);
237 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
239 EXPECT_THAT(tmap[
"default"], EqualsProto(R
"(
241 tensor_shape { dim { size: 1 } }
246 TF_EXPECT_OK(FillPredictRequestFromJson(
247 absl::Substitute(R
"({ "instances": [$0] })",
248 -std::numeric_limits<double>::max()),
249 getmap(infomap), &req, &format));
251 EXPECT_EQ(tmap.size(), 1);
252 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
254 EXPECT_THAT(tmap["default"], EqualsProto(R
"(
256 tensor_shape { dim { size: 1 } }
261 TEST(JsontensorTest, FloatTensorThatExceedsMinReturnsZero) {
262 TensorInfoMap infomap;
264 TextFormat::ParseFromString("dtype: DT_FLOAT", &infomap[
"default"]));
267 JsonPredictRequestFormat format;
268 TF_EXPECT_OK(FillPredictRequestFromJson(
269 absl::Substitute(R
"({ "instances": [$0] })",
270 std::numeric_limits<double>::min()),
271 getmap(infomap), &req, &format));
272 auto tmap = req.inputs();
273 EXPECT_EQ(tmap.size(), 1);
274 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
276 EXPECT_THAT(tmap[
"default"], EqualsProto(R
"(
278 tensor_shape { dim { size: 1 } }
283 TF_EXPECT_OK(FillPredictRequestFromJson(
284 absl::Substitute(R
"({ "instances": [$0] })",
285 -std::numeric_limits<double>::min()),
286 getmap(infomap), &req, &format));
288 EXPECT_EQ(tmap.size(), 1);
289 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
291 EXPECT_THAT(tmap["default"], EqualsProto(R
"(
293 tensor_shape { dim { size: 1 } }
298 TEST(JsontensorTest, SingleUnnamedTensorWithSignature) {
299 TensorInfoMap infomap;
301 TextFormat::ParseFromString("dtype: DT_INT32", &infomap[
"default"]));
304 JsonPredictRequestFormat format;
305 TF_EXPECT_OK(FillPredictRequestFromJson(R
"(
307 "signature_name": "predict_images",
310 getmap(infomap), &req, &format));
311 EXPECT_EQ(req.model_spec().signature_name(), "predict_images");
312 auto tmap = req.inputs();
313 EXPECT_EQ(tmap.size(), 1);
314 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
315 EXPECT_THAT(tmap[
"default"], EqualsProto(R
"(
326 TEST(JsontensorTest, TensorFromNonNullTerminatedBuffer) {
327 TensorInfoMap infomap;
329 TextFormat::ParseFromString("dtype: DT_INT32", &infomap[
"default"]));
332 const string jsonstr = R
"({"instances": [[1,2],[3,4],[5,6]]}X)";
334 JsonPredictRequestFormat format;
335 TF_EXPECT_OK(FillPredictRequestFromJson(
337 absl::string_view(jsonstr.data(), jsonstr.length() - 1), getmap(infomap),
339 auto tmap = req.inputs();
340 EXPECT_EQ(tmap.size(), 1);
341 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
342 EXPECT_THAT(tmap[
"default"], EqualsProto(R
"(
357 TEST(JsontensorTest, SingleUnnamedTensorBase64Scalars) {
358 TensorInfoMap infomap;
360 TextFormat::ParseFromString("dtype: DT_STRING", &infomap[
"default"]));
363 JsonPredictRequestFormat format;
364 TF_EXPECT_OK(FillPredictRequestFromJson(R
"(
366 "instances": [ { "b64" : "aGVsbG8=" }, { "b64": "d29ybGQ=" } ]
368 getmap(infomap), &req, &format));
369 auto tmap = req.inputs();
370 EXPECT_EQ(tmap.size(), 1);
371 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
372 EXPECT_THAT(tmap[
"default"], EqualsProto(R
"(
382 TEST(JsontensorTest, SingleUnnamedTensorBase64Lists) {
383 TensorInfoMap infomap;
385 TextFormat::ParseFromString("dtype: DT_STRING", &infomap[
"default"]));
388 JsonPredictRequestFormat format;
389 TF_EXPECT_OK(FillPredictRequestFromJson(R
"(
391 "instances": [ [{ "b64" : "aGVsbG8=" }], [{ "b64": "d29ybGQ=" }] ]
393 getmap(infomap), &req, &format));
394 auto tmap = req.inputs();
395 EXPECT_EQ(tmap.size(), 1);
396 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
397 EXPECT_THAT(tmap[
"default"], EqualsProto(R
"(
408 TEST(JsontensorTest, SingleNamedTensorBase64) {
409 TensorInfoMap infomap;
411 TextFormat::ParseFromString("dtype: DT_STRING", &infomap[
"default"]));
414 JsonPredictRequestFormat format;
415 TF_EXPECT_OK(FillPredictRequestFromJson(R
"(
419 "default": [ [{ "b64" : "aGVsbG8=" }], [{ "b64": "d29ybGQ=" }] ]
423 getmap(infomap), &req, &format));
424 auto tmap = req.inputs();
425 EXPECT_EQ(tmap.size(), 1);
426 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
427 EXPECT_THAT(tmap[
"default"], EqualsProto(R
"(
439 TEST(JsontensorTest, MultipleNamedTensor) {
440 TensorInfoMap infomap;
444 TextFormat::ParseFromString(
"dtype: DT_INT32", &infomap[
"int_tensor"]));
446 TextFormat::ParseFromString(
"dtype: DT_STRING", &infomap[
"str_tensor"]));
448 TextFormat::ParseFromString(
"dtype: DT_FLOAT", &infomap[
"float_tensor"]));
450 TextFormat::ParseFromString(
"dtype: DT_DOUBLE", &infomap[
"dbl_tensor"]));
453 JsonPredictRequestFormat format;
454 TF_EXPECT_OK(FillPredictRequestFromJson(R
"(
458 "int_tensor": [[1,2],[3,4],[5,6]],
459 "str_tensor": ["foo", "bar"],
460 "float_tensor": [1.0, NaN],
464 "int_tensor": [[7,8],[9,0],[1,2]],
465 "str_tensor": ["baz", "bat"],
466 "float_tensor": [2.0, Infinity],
471 getmap(infomap), &req, &format));
473 auto tmap = req.inputs();
474 EXPECT_EQ(tmap.size(), 4);
475 EXPECT_EQ(format, JsonPredictRequestFormat::kRow);
476 EXPECT_THAT(tmap[
"int_tensor"], EqualsProto(R
"(
496 EXPECT_THAT(tmap["str_tensor"], EqualsProto(R
"(
507 EXPECT_THAT(tmap["float_tensor"], EqualsProto(R
"(
518 EXPECT_THAT(tmap["dbl_tensor"], EqualsProto(R
"(
529 TEST(JsontensorTest, SingleUnnamedTensorColumnarFormat) {
530 TensorInfoMap infomap;
532 TextFormat::ParseFromString("dtype: DT_INT32", &infomap[
"int_tensor"]));
535 JsonPredictRequestFormat format;
536 TF_EXPECT_OK(FillPredictRequestFromJson(R
"(
539 "int_tensor": [[[1,2],[3,4],[5,6]]]
542 getmap(infomap), &req, &format));
543 auto tmap = req.inputs();
544 EXPECT_EQ(tmap.size(), 1);
545 EXPECT_EQ(format, JsonPredictRequestFormat::kColumnar);
546 EXPECT_THAT(tmap[
"int_tensor"], EqualsProto(R
"(
565 TF_EXPECT_OK(FillPredictRequestFromJson(R
"(
567 "inputs": [[[1,2],[3,4],[5,6]]]
569 getmap(infomap), &req, &format));
570 auto tmap2 = req.inputs();
571 EXPECT_EQ(tmap2.size(), 1);
572 EXPECT_EQ(format, JsonPredictRequestFormat::kColumnar);
573 EXPECT_THAT(tmap2[
"int_tensor"], EqualsProto(R
"(
589 TEST(JsontensorTest, MultipleNamedTensorColumnarFormat) {
590 TensorInfoMap infomap;
594 TextFormat::ParseFromString(
"dtype: DT_INT32", &infomap[
"int_tensor"]));
596 TextFormat::ParseFromString(
"dtype: DT_STRING", &infomap[
"str_tensor"]));
598 TextFormat::ParseFromString(
"dtype: DT_STRING", &infomap[
"bin_tensor"]));
601 JsonPredictRequestFormat format;
602 TF_EXPECT_OK(FillPredictRequestFromJson(R
"(
605 "int_tensor": [[[1,2],[3,4],[5,6]]],
606 "str_tensor": ["foo", "bar"],
607 "bin_tensor": { "b64" : "aGVsbG8=" }
610 getmap(infomap), &req, &format));
612 auto tmap = req.inputs();
613 EXPECT_EQ(tmap.size(), 3);
614 EXPECT_EQ(format, JsonPredictRequestFormat::kColumnar);
615 EXPECT_THAT(tmap[
"int_tensor"], EqualsProto(R
"(
629 EXPECT_THAT(tmap["str_tensor"], EqualsProto(R
"(
631 tensor_shape { dim { size: 2 } }
635 EXPECT_THAT(tmap["bin_tensor"], EqualsProto(R
"(
642 TEST(JsontensorTest, SingleUnnamedTensorErrors) {
643 TensorInfoMap infomap;
645 TextFormat::ParseFromString("dtype: DT_INT32", &infomap[
"default"]));
648 JsonPredictRequestFormat format;
650 status = FillPredictRequestFromJson(
"", getmap(infomap), &req, &format);
651 ASSERT_TRUE(errors::IsInvalidArgument(status));
652 EXPECT_THAT(status.message(), HasSubstr(
"document is empty"));
654 status = FillPredictRequestFromJson(R
"(
657 "instances": [[1,2],[3,4],[5,6,7]]
659 getmap(infomap), &req, &format);
660 ASSERT_TRUE(errors::IsInvalidArgument(status));
661 EXPECT_THAT(status.message(), HasSubstr("must be a string value"));
663 status = FillPredictRequestFromJson(R
"(
665 "instances": [[1,2],[3,4],[5,6,7]],
666 "inputs": [[1,2],[3,4],[5,6,7]]
668 getmap(infomap), &req, &format);
669 ASSERT_TRUE(errors::IsInvalidArgument(status));
670 EXPECT_THAT(status.message(), HasSubstr("Not formatted correctly"));
672 status = FillPredictRequestFromJson(R
"(
674 "instances": [[1,2],[3,4],[5,6,7]]
676 getmap(infomap), &req, &format);
677 ASSERT_TRUE(errors::IsInvalidArgument(status));
678 EXPECT_THAT(status.message(), HasSubstr("Expecting tensor size"));
680 status = FillPredictRequestFromJson(R
"(
682 "instances": [[1,2],[3,4],[[5,6]]]
684 getmap(infomap), &req, &format);
685 ASSERT_TRUE(errors::IsInvalidArgument(status));
686 EXPECT_THAT(status.message(), HasSubstr("Expecting shape"));
688 status = FillPredictRequestFromJson(R
"(
690 "instances": [1, [1]]
692 getmap(infomap), &req, &format);
693 ASSERT_TRUE(errors::IsInvalidArgument(status));
694 EXPECT_THAT(status.message(), HasSubstr("Expecting shape"));
696 status = FillPredictRequestFromJson(R
"(
698 "instances": [[1,2],["a", "b"]]
700 getmap(infomap), &req, &format);
701 ASSERT_TRUE(errors::IsInvalidArgument(status));
702 EXPECT_THAT(status.message(), HasSubstr("not of expected type"));
705 TEST(JsontensorTest, MultipleNamedTensorErrors) {
706 TensorInfoMap infomap;
710 TextFormat::ParseFromString(
"dtype: DT_INT32", &infomap[
"int_tensor"]));
712 TextFormat::ParseFromString(
"dtype: DT_STRING", &infomap[
"str_tensor"]));
715 JsonPredictRequestFormat format;
718 status = FillPredictRequestFromJson(R
"(
722 "int_tensor": [[1,2],[3,4],[5,6]],
723 "str_tensor": ["foo", "bar"]
726 "int_tensor": [[[7,8],[9,0],[1,2]]],
727 "str_tensor": ["baz", "bat"]
731 getmap(infomap), &req, &format);
732 ASSERT_TRUE(errors::IsInvalidArgument(status));
733 EXPECT_THAT(status.message(), HasSubstr("Expecting shape"));
737 status = FillPredictRequestFromJson(R
"(
741 "int_tensor": [[1,2],[3,4],[5,6],[7,8]],
742 "str_tensor": ["foo", "bar"]
745 "int_tensor": [[7,8],[9,0],[1,2]],
746 "str_tensor": ["baz", "bat"]
750 getmap(infomap), &req, &format);
751 ASSERT_TRUE(errors::IsInvalidArgument(status));
752 EXPECT_THAT(status.message(), HasSubstr("Expecting tensor size"));
757 status = FillPredictRequestFromJson(R
"(
761 "int_tensor": [[1,2],[3,4],[5,6]],
762 "str_tensor": ["foo", "bar"]
766 "int_tensor": [[[7,8],[9,0],[1,2]]],
767 "str_tensor": ["baz", "bat"]
771 getmap(infomap), &req, &format);
772 ASSERT_TRUE(errors::IsInvalidArgument(status));
773 EXPECT_THAT(status.message(), HasSubstr("Expecting object but got list"));
779 TextFormat::ParseFromString(
"dtype: DT_STRING", &infomap[
"str_tensor"]));
781 status = FillPredictRequestFromJson(R
"(
786 "str_tensor": ["baz", "bat"]
790 getmap(infomap), &req, &format);
791 ASSERT_TRUE(errors::IsInvalidArgument(status));
792 EXPECT_THAT(status.message(),
793 HasSubstr("Expecting value/list but got object"));
796 template <const
unsigned int parseflags = rap
idjson::kParseNanAndInfFlag>
797 Status CompareJson(
const string& json1,
const string& json2) {
798 rapidjson::Document doc1;
799 if (doc1.Parse<parseflags>(json1.c_str()).HasParseError()) {
800 return errors::InvalidArgument(
801 "LHS JSON Parse error: ",
802 rapidjson::GetParseError_En(doc1.GetParseError()),
803 " at offset: ", doc1.GetErrorOffset(),
" JSON: ", json1);
805 rapidjson::Document doc2;
806 if (doc2.Parse<parseflags>(json2.c_str()).HasParseError()) {
807 return errors::InvalidArgument(
808 "RHS JSON Parse error: ",
809 rapidjson::GetParseError_En(doc2.GetParseError()),
810 " at offset: ", doc2.GetErrorOffset(),
" JSON: ", json2);
813 return errors::InvalidArgument(
"JSON Different. JSON1: ", json1,
826 Status CompareJsonAllValuesAsStrings(
const string& json1,
const string& json2) {
827 return CompareJson<rapidjson::kParseNanAndInfFlag |
828 rapidjson::kParseNumbersAsStringsFlag>(json1, json2);
831 TEST(JsontensorTest, FromJsonSingleTensor) {
833 ASSERT_TRUE(TextFormat::ParseFromString(R
"(
853 &tensormap["int_tensor"]));
857 MakeJsonFromTensors(tensormap, JsonPredictRequestFormat::kRow, &json));
858 TF_EXPECT_OK(CompareJson(json, R
"({
859 "predictions": [[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 0], [1, 2]]
863 TF_EXPECT_OK(MakeJsonFromTensors(tensormap,
864 JsonPredictRequestFormat::kColumnar, &json));
865 TF_EXPECT_OK(CompareJson(json, R"({
866 "outputs": [[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 0], [1, 2]]
870 TEST(JsontensorTest, FromJsonSingleScalarTensor) {
872 ASSERT_TRUE(TextFormat::ParseFromString(R"(
883 &tensormap["int_tensor"]));
887 MakeJsonFromTensors(tensormap, JsonPredictRequestFormat::kRow, &json));
888 TF_EXPECT_OK(CompareJson(json, R
"({ "predictions": [1, 2, 3, 4, 5] })"));
891 TF_EXPECT_OK(MakeJsonFromTensors(tensormap,
892 JsonPredictRequestFormat::kColumnar, &json));
893 TF_EXPECT_OK(CompareJson(json, R"({ "outputs": [1, 2, 3, 4, 5] })"));
896 TEST(JsontensorTest, FromJsonSingleBytesTensor) {
898 ASSERT_TRUE(TextFormat::ParseFromString(R"(
907 string_val: "serving"
909 &tensormap["str_tensor_bytes"]));
913 MakeJsonFromTensors(tensormap, JsonPredictRequestFormat::kRow, &json));
914 TF_EXPECT_OK(CompareJson(json, R
"({
916 [{"b64": "aGVsbG8="}, {"b64": "d29ybGQ="}],
917 [{"b64": "dGY="}, {"b64": "c2VydmluZw=="}]
923 TEST(JsontensorTest, FromJsonSingleFloatTensorSixDigitPrecision) {
925 ASSERT_TRUE(TextFormat::ParseFromString(R
"(
938 &tensormap["float_tensor"]));
942 MakeJsonFromTensors(tensormap, JsonPredictRequestFormat::kRow, &json));
943 TF_EXPECT_OK(CompareJsonAllValuesAsStrings(json, R
"({
945 [9e+06, 999999.0, 0.5],
946 [0.0003, 3e-05, 555557.5]
950 TEST(JsontensorTest, FromJsonSingleFloatTensorNonFinite) {
952 ASSERT_TRUE(TextFormat::ParseFromString(R"(
963 &tensormap["float_tensor"]));
967 MakeJsonFromTensors(tensormap, JsonPredictRequestFormat::kRow, &json));
968 TF_EXPECT_OK(CompareJsonAllValuesAsStrings(json, R
"({
975 TEST(JsontensorTest, FromJsonSingleTensorErrors) {
981 MakeJsonFromTensors(tensormap, JsonPredictRequestFormat::kRow, &json);
982 ASSERT_TRUE(errors::IsInvalidArgument(status));
983 EXPECT_THAT(status.message(), HasSubstr(
"empty tensor map"));
985 ASSERT_TRUE(TextFormat::ParseFromString(R
"(
993 &tensormap["tensor"]));
995 MakeJsonFromTensors(tensormap, JsonPredictRequestFormat::kRow, &json);
996 ASSERT_TRUE(errors::IsInvalidArgument(status));
997 EXPECT_THAT(status.message(), HasSubstr(
"tensor type: complex64"));
999 ASSERT_TRUE(TextFormat::ParseFromString(R
"(
1003 &tensormap["tensor"]));
1005 MakeJsonFromTensors(tensormap, JsonPredictRequestFormat::kRow, &json);
1006 ASSERT_TRUE(errors::IsInvalidArgument(status));
1007 EXPECT_THAT(status.message(), HasSubstr(
"no shape information"));
1010 TEST(JsontensorTest, FromJsonMultipleNamedTensors) {
1011 TensorMap tensormap;
1012 ASSERT_TRUE(TextFormat::ParseFromString(R
"(
1032 &tensormap["int_tensor"]));
1034 ASSERT_TRUE(TextFormat::ParseFromString(R
"(
1045 &tensormap["str_tensor"]));
1047 ASSERT_TRUE(TextFormat::ParseFromString(R
"(
1056 &tensormap["float_tensor"]));
1058 ASSERT_TRUE(TextFormat::ParseFromString(R
"(
1066 &tensormap["double_scalar_tensor"]));
1068 ASSERT_TRUE(TextFormat::ParseFromString(R
"(
1077 string_val: "serving"
1079 &tensormap["str_tensor_bytes"]));
1083 MakeJsonFromTensors(tensormap, JsonPredictRequestFormat::kRow, &json));
1084 TF_EXPECT_OK(CompareJson(json, R
"({
1087 "double_scalar_tensor": 8.0,
1088 "float_tensor": [1.0],
1089 "int_tensor": [[1, 2], [3, 4], [5, 6]],
1090 "str_tensor": ["foo", "bar"],
1091 "str_tensor_bytes": [ {"b64": "aGVsbG8="}, {"b64": "d29ybGQ="} ]
1094 "double_scalar_tensor": 9.0,
1095 "float_tensor": [2.0],
1096 "int_tensor": [[7, 8], [9, 0], [1, 2]],
1097 "str_tensor": ["baz", "bat"],
1098 "str_tensor_bytes": [ {"b64": "dGY="}, {"b64": "c2VydmluZw=="} ]
1103 TF_EXPECT_OK(MakeJsonFromTensors(tensormap,
1104 JsonPredictRequestFormat::kColumnar, &json));
1105 TF_EXPECT_OK(CompareJson(json, R"({
1107 "double_scalar_tensor": [8.0, 9.0],
1108 "float_tensor": [[1.0], [2.0]],
1109 "int_tensor": [[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 0], [1, 2]]],
1110 "str_tensor": [["foo", "bar"], ["baz", "bat"]],
1111 "str_tensor_bytes": [[{"b64": "aGVsbG8="}, {"b64": "d29ybGQ="}],
1112 [{"b64": "dGY="}, {"b64": "c2VydmluZw=="}]]
1116 TEST(JsontensorTest, FromJsonMultipleNamedTensorsErrors) {
1117 TensorMap tensormap;
1118 ASSERT_TRUE(TextFormat::ParseFromString(R"(
1131 &tensormap["int_tensor"]));
1133 ASSERT_TRUE(TextFormat::ParseFromString(R
"(
1143 &tensormap["str_tensor"]));
1146 const auto& status =
1147 MakeJsonFromTensors(tensormap, JsonPredictRequestFormat::kRow, &json);
1148 ASSERT_TRUE(errors::IsInvalidArgument(status));
1149 EXPECT_THAT(status.message(), HasSubstr(
"inconsistent batch size"));
1152 TEST(JsontensorTest, FromJsonSingleZeroBatchTensor) {
1153 TensorMap tensormap;
1154 ASSERT_TRUE(TextFormat::ParseFromString(R
"(
1161 &tensormap["int_tensor"]));
1165 MakeJsonFromTensors(tensormap, JsonPredictRequestFormat::kRow, &json));
1166 TF_EXPECT_OK(CompareJson(json, R
"({ "predictions": [] })"));
1169 TEST(JsontensorTest, FromJsonMultipleZeroBatchTensors) {
1170 TensorMap tensormap;
1171 ASSERT_TRUE(TextFormat::ParseFromString(R"(
1179 &tensormap["str_tensor"]));
1181 ASSERT_TRUE(TextFormat::ParseFromString(R
"(
1189 &tensormap["float_tensor"]));
1193 MakeJsonFromTensors(tensormap, JsonPredictRequestFormat::kRow, &json));
1194 TF_EXPECT_OK(CompareJson(json, R
"({ "predictions": [] })"));
1197 TEST(JsontensorTest, FromJsonMultipleZeroBatchTensorsErrors) {
1198 TensorMap tensormap;
1199 ASSERT_TRUE(TextFormat::ParseFromString(R"(
1206 &tensormap["int_tensor"]));
1208 ASSERT_TRUE(TextFormat::ParseFromString(R
"(
1217 &tensormap["str_tensor"]));
1220 const auto& status =
1221 MakeJsonFromTensors(tensormap, JsonPredictRequestFormat::kRow, &json);
1222 ASSERT_TRUE(errors::IsInvalidArgument(status));
1223 EXPECT_THAT(status.message(), HasSubstr(
"inconsistent batch size"));
1226 template <
typename RequestType>
1227 class ClassifyRegressRequestTest :
public ::testing::Test {
1229 Status FillRequest(
const string& json, ClassificationRequest* req) {
1230 return FillClassificationRequestFromJson(json, req);
1233 Status FillRequest(
const string& json, RegressionRequest* req) {
1234 return FillRegressionRequestFromJson(json, req);
1238 typedef ::testing::Types<ClassificationRequest, RegressionRequest> RequestTypes;
1239 TYPED_TEST_CASE(ClassifyRegressRequestTest, RequestTypes);
1241 TYPED_TEST(ClassifyRegressRequestTest, RequestNoContext) {
1243 TF_EXPECT_OK(this->FillRequest(R
"(
1247 "names": [ "foo", "bar" ],
1248 "ratings": [ 8.0, 9.0 ],
1259 TypeParam expected_req;
1260 ASSERT_TRUE(TextFormat::ParseFromString(R"(
1267 value { bytes_list {
1274 value { float_list {
1281 value { int64_list {
1291 value { bytes_list {
1297 value { float_list {
1307 EXPECT_TRUE(MessageDifferencer::ApproximatelyEquals(req, expected_req))
1308 << "Expected Proto: " << expected_req.DebugString();
1311 TYPED_TEST(ClassifyRegressRequestTest, RequestWithContextAndSignature) {
1313 TF_EXPECT_OK(this->FillRequest(R
"(
1315 "signature_name": "custom_signture",
1318 "location": [ "sfo" ]
1322 "names": [ "foo", "bar" ],
1323 "ratings": [ 8.0, 9.0, NaN, Infinity ],
1327 "names": [ "baz", { "b64": "aGVsbG8=" } ],
1329 "intboolmix": [ 1, true, false ]
1333 "ratings": -Infinity
1339 TypeParam expected_req;
1340 ASSERT_TRUE(TextFormat::ParseFromString(R"(
1342 signature_name: "custom_signture"
1345 example_list_with_context {
1350 value { bytes_list {
1356 value { bytes_list {
1366 value { bytes_list {
1373 value { float_list {
1382 value { int64_list {
1392 value { bytes_list {
1399 value { float_list {
1405 value { int64_list {
1417 value { bytes_list {
1423 value { float_list {
1434 DefaultFieldComparator comparator;
1435 comparator.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
1436 comparator.set_treat_nan_as_equal(true);
1437 MessageDifferencer differencer;
1438 differencer.set_field_comparator(&comparator);
1439 EXPECT_TRUE(differencer.Compare(req, expected_req))
1440 <<
"Expected proto: " << expected_req.DebugString()
1441 <<
"But got proto: " << req.DebugString();
1444 TYPED_TEST(ClassifyRegressRequestTest, JsonErrors) {
1446 auto status = this->FillRequest(R
"(
1448 "signature_name": [ "hello" ],
1449 "examples": [ { "names": [ "foo", "bar" ] } ]
1452 ASSERT_TRUE(errors::IsInvalidArgument(status));
1453 EXPECT_THAT(status.message(),
1454 HasSubstr("'signature_name' key must be a string"));
1457 status = this->FillRequest(R
"(
1459 "context": [ { "names": [ "foo", "bar" ] } ]
1462 ASSERT_TRUE(errors::IsInvalidArgument(status));
1463 EXPECT_THAT(status.message(), HasSubstr("Example must be JSON object"));
1466 status = this->FillRequest(R
"(
1468 "examples": { "names": [ "foo", "bar" ] }
1471 ASSERT_TRUE(errors::IsInvalidArgument(status));
1472 EXPECT_THAT(status.message(), HasSubstr("list/array"));
1475 status = this->FillRequest(R
"(
1477 "examples": [ [ { "names": [ "foo", "bar" ] } ] ]
1480 ASSERT_TRUE(errors::IsInvalidArgument(status));
1481 EXPECT_THAT(status.message(), HasSubstr("Example must be JSON object"));
1484 status = this->FillRequest(R
"(
1486 "examples": [ { "names": [ 10, null ] } ]
1489 ASSERT_TRUE(errors::IsInvalidArgument(status));
1490 EXPECT_THAT(status.message(),
1491 HasSubstr("names has element with unexpected JSON type: Null"));
1494 status = this->FillRequest(R
"(
1496 "examples": [ { "names": [ 10, 10.0 ] } ]
1499 ASSERT_TRUE(errors::IsInvalidArgument(status));
1500 EXPECT_THAT(status.message(),
1501 HasSubstr("feature: names expecting type: int64"));
1504 status = this->FillRequest(R
"(
1506 "examples": [ { "names": [ 10, { "test": 10 } ] } ]
1509 ASSERT_TRUE(errors::IsInvalidArgument(status));
1510 EXPECT_THAT(status.message(),
1511 HasSubstr("names has element with unexpected JSON type: Object"));
1514 status = this->FillRequest(R
"(
1516 "examples": [ { "names": [ [10], 20 ] } ]
1519 ASSERT_TRUE(errors::IsInvalidArgument(status));
1520 EXPECT_THAT(status.message(),
1521 HasSubstr("names has element with unexpected JSON type: Array"));
1524 status = this->FillRequest(R
"(
1526 "examples": [ { "names": [ 20, 18446744073709551603 ] } ]
1529 ASSERT_TRUE(errors::IsInvalidArgument(status));
1530 EXPECT_THAT(status.message(), HasSubstr("Only int64_t is supported"));
1533 TEST(ClassifyRegressnResultTest, JsonFromClassificationResult) {
1534 ClassificationResult result;
1535 ASSERT_TRUE(TextFormat::ParseFromString(R
"(
1537 classes { label: "car" score: 0.2 }
1538 classes { label: "bike" score: 0.7 }
1539 classes { label: "bus" score: 0.1 }
1542 classes { label: "car" score: 0.7 }
1543 classes { label: "bike" score: 0.1 }
1544 classes { label: "bus" score: 0.2 }
1549 TF_EXPECT_OK(MakeJsonFromClassificationResult(result, &json));
1550 TF_EXPECT_OK(CompareJson(json, R
"({
1552 [ ["car", 0.2], ["bike", 0.7], ["bus", 0.1] ],
1553 [ ["car", 0.7], ["bike", 0.1], ["bus", 0.2] ]
1558 TEST(ClassifyRegressnResultTest, JsonFromRegressionResult) {
1559 RegressionResult result;
1560 ASSERT_TRUE(TextFormat::ParseFromString(R"(
1561 regressions { value: 0.2 }
1562 regressions { value: 0.9 }
1563 regressions { value: 1.0 }
1568 TF_EXPECT_OK(MakeJsonFromRegressionResult(result, &json));
1569 TF_EXPECT_OK(CompareJson(json, R
"({ "results": [ 0.2, 0.9, 1.0 ] })"));
1572 TEST(ClassifyRegressnResultTest, JsonFromRegressionResultWithNonFinite) {
1573 RegressionResult result;
1574 ASSERT_TRUE(TextFormat::ParseFromString(R"(
1575 regressions { value: 0.2 }
1576 regressions { value: Infinity }
1577 regressions { value: 1.0 }
1578 regressions { value: -Infinity }
1579 regressions { value: NaN }
1584 TF_EXPECT_OK(MakeJsonFromRegressionResult(result, &json));
1585 TF_EXPECT_OK(CompareJsonAllValuesAsStrings(
1586 json, R
"({ "results": [ 0.2, Infinity, 1.0, -Infinity, NaN ] })"));
1589 TEST(ClassifyRegressnResultTest, JsonFromResultErrors) {
1591 auto status = MakeJsonFromClassificationResult(ClassificationResult(), &json);
1592 ASSERT_TRUE(errors::IsInvalidArgument(status));
1593 EXPECT_THAT(status.message(), HasSubstr(
"empty ClassificationResults"));
1595 status = MakeJsonFromRegressionResult(RegressionResult(), &json);
1596 ASSERT_TRUE(errors::IsInvalidArgument(status));
1597 EXPECT_THAT(status.message(), HasSubstr(
"empty RegressionResults"));
1600 TEST(MakeJsonFromTensors, StatusOK) {
1602 MakeJsonFromStatus(OkStatus(), &json);
1603 EXPECT_EQ(json,
"");
1606 TEST(MakeJsonFromTensors, StatusError) {
1608 MakeJsonFromStatus(errors::InvalidArgument(
"Bad key: \"key\""), &json);
1609 TF_EXPECT_OK(CompareJson(json, R
"({ "error": "Bad key: \"key\"" })"));
1612 MakeJsonFromStatus(errors::InvalidArgument("Bad key: 'key'"), &json);
1613 TF_EXPECT_OK(CompareJson(json, R
"({ "error": "Bad key: 'key'" })"));