22 #include "google/protobuf/map.h" 
   23 #include "tensorflow/cc/saved_model/signature_constants.h" 
   24 #include "tensorflow/core/example/example.pb.h" 
   25 #include "tensorflow/core/example/feature.pb.h" 
   26 #include "tensorflow/core/framework/types.pb.h" 
   27 #include "tensorflow/core/lib/core/errors.h" 
   28 #include "tensorflow/core/lib/core/status.h" 
   29 #include "tensorflow/core/lib/core/status_test_util.h" 
   30 #include "tensorflow/core/platform/mutex.h" 
   31 #include "tensorflow/core/platform/threadpool_options.h" 
   32 #include "tensorflow/core/platform/types.h" 
   33 #include "tensorflow/core/protobuf/error_codes.pb.h" 
   34 #include "tensorflow/core/public/session.h" 
   35 #include "tensorflow/core/tfrt/utils/tensor_util.h" 
   36 #include "tsl/platform/errors.h" 
   37 #include "tensorflow_serving/apis/input.pb.h" 
   38 #include "tensorflow_serving/apis/model.pb.h" 
   39 #include "tensorflow_serving/apis/regression.pb.h" 
   40 #include "tensorflow_serving/config/model_server_config.pb.h" 
   41 #include "tensorflow_serving/core/availability_preserving_policy.h" 
   42 #include "tensorflow_serving/model_servers/model_platform_types.h" 
   43 #include "tensorflow_serving/model_servers/platform_config_util.h" 
   44 #include "tensorflow_serving/model_servers/server_core.h" 
   45 #include "tensorflow_serving/servables/tensorflow/session_bundle_config.pb.h" 
   46 #include "tensorflow_serving/servables/tensorflow/test_util/mock_tfrt_saved_model.h" 
   47 #include "tensorflow_serving/servables/tensorflow/tfrt_regressor.h" 
   48 #include "tensorflow_serving/servables/tensorflow/tfrt_saved_model_source_adapter.pb.h" 
   49 #include "tensorflow_serving/servables/tensorflow/tfrt_servable.h" 
   50 #include "tensorflow_serving/test_util/test_util.h" 
   52 namespace tensorflow {
 
   57 using ::testing::DoAll;
 
   58 using ::testing::HasSubstr;
 
   59 using ::testing::Return;
 
   60 using ::testing::WithArgs;
 
   62 constexpr 
char kTestModelName[] = 
"test_model";
 
   63 constexpr 
int kTestModelVersion = 123;
 
   65 class TfrtRegressorTest : 
public ::testing::Test {
 
   67   static void SetUpTestSuite() {
 
   68     tfrt_stub::SetGlobalRuntime(
 
   69         tfrt_stub::Runtime::Create(4));
 
   72   void SetUp()
 override {
 
   73     ModelServerConfig config;
 
   74     auto model_config = config.mutable_model_config_list()->add_config();
 
   75     model_config->set_name(kTestModelName);
 
   76     model_config->set_base_path(
 
   77         test_util::TestSrcDirPath(
"servables/tensorflow/" 
   78                                   "testdata/saved_model_half_plus_two_cpu"));
 
   79     model_config->set_model_platform(kTensorFlowModelPlatform);
 
   83     ServerCore::Options options;
 
   84     options.model_server_config = config;
 
   85     PlatformConfigMap platform_config_map;
 
   86     ::google::protobuf::Any source_adapter_config;
 
   87     TfrtSavedModelSourceAdapterConfig saved_model_bundle_source_adapter_config;
 
   88     source_adapter_config.PackFrom(saved_model_bundle_source_adapter_config);
 
   89     (*(*platform_config_map
 
   90             .mutable_platform_configs())[kTensorFlowModelPlatform]
 
   91           .mutable_source_adapter_config()) = source_adapter_config;
 
   92     options.platform_config_map = platform_config_map;
 
   93     options.aspired_version_policy =
 
   94         std::unique_ptr<AspiredVersionPolicy>(
new AvailabilityPreservingPolicy);
 
   97     options.num_initial_load_threads = options.num_load_threads;
 
  100     request_ = test_util::CreateProto<RegressionRequest>(
 
  102         "  name: \"test_model\"" 
  103         "  signature_name: \"regress_x_to_y\"" 
  123   static void TearDownTestSuite() { server_core_ = 
nullptr; }
 
  126   Status GetSavedModelServableHandle(ServerCore* server_core,
 
  127                                      ServableHandle<Servable>* servable) {
 
  128     ModelSpec model_spec;
 
  129     model_spec.set_name(kTestModelName);
 
  130     return server_core->GetServableHandle(model_spec, servable);
 
  133   Status CallRegress(ServerCore* server_core, 
const RegressionRequest& request,
 
  134                      RegressionResponse* response) {
 
  135     ServableHandle<Servable> servable;
 
  136     TF_RETURN_IF_ERROR(GetSavedModelServableHandle(server_core, &servable));
 
  137     tfrt::SavedModel::RunOptions run_options;  
 
  139         run_options, kTestModelVersion,
 
  140         &(down_cast<TfrtSavedModelServable*>(servable.get()))->saved_model(),
 
  144   static std::unique_ptr<ServerCore> server_core_;
 
  146   RegressionRequest request_;
 
  149 std::unique_ptr<ServerCore> TfrtRegressorTest::server_core_;
 
  151 TEST_F(TfrtRegressorTest, Basic) {
 
  152   auto request = test_util::CreateProto<RegressionRequest>(
 
  154       "  name: \"test_model\"" 
  155       "  signature_name: \"regress_x_to_y\"" 
  173       "              value: [ \"pt_BR\" ]" 
  201   RegressionResponse response;
 
  203   TF_EXPECT_OK(CallRegress(server_core_.get(), request, &response));
 
  206       test_util::EqualsProto(
 
  207           "result { regressions { value: 42 } regressions { value: 12 }}" 
  209           "  name: \"test_model\"" 
  210           "  signature_name: \"regress_x_to_y\"" 
  211           "  version { value: 123 }" 
  215 TEST_F(TfrtRegressorTest, BasicWithContext) {
 
  216   auto request = test_util::CreateProto<RegressionRequest>(
 
  218       "  name: \"test_model\"" 
  219       "  signature_name: \"regress_x_to_y\"" 
  222       "   example_list_with_context {" 
  237       "              value: [ \"pt_BR\" ]" 
  277   RegressionResponse response;
 
  279   TF_EXPECT_OK(CallRegress(server_core_.get(), request, &response));
 
  282       test_util::EqualsProto(
 
  283           "result { regressions { value: 42 } regressions { value: 12 }}" 
  285           "  name: \"test_model\"" 
  286           "  signature_name: \"regress_x_to_y\"" 
  287           "  version { value: 123 }" 
  291 TEST_F(TfrtRegressorTest, EmptyExampleList) {
 
  292   auto request = test_util::CreateProto<RegressionRequest>(
 
  294       "  name: \"test_model\"" 
  295       "  signature_name: \"regress_x_to_y\"" 
  301   RegressionResponse response;
 
  303   Status status = CallRegress(server_core_.get(), request, &response);
 
  304   EXPECT_EQ(status.code(), error::INVALID_ARGUMENT);
 
  305   EXPECT_THAT(status.message(), ::testing::HasSubstr(
"Input is empty"));
 
  308 TEST_F(TfrtRegressorTest, EmptyExampleListWithContext) {
 
  309   auto request = test_util::CreateProto<RegressionRequest>(
 
  311       "  name: \"test_model\"" 
  312       "  signature_name: \"regress_x_to_y\"" 
  315       "  example_list_with_context {" 
  330   RegressionResponse response;
 
  332   Status status = CallRegress(server_core_.get(), request, &response);
 
  333   EXPECT_EQ(status.code(), error::INVALID_ARGUMENT);
 
  334   EXPECT_THAT(status.message(), ::testing::HasSubstr(
"Input is empty"));
 
  337 TEST_F(TfrtRegressorTest, EmptyInput) {
 
  338   auto request = test_util::CreateProto<RegressionRequest>(
 
  340       "  name: \"test_model\"" 
  341       "  signature_name: \"regress_x_to_y\"" 
  345   RegressionResponse response;
 
  347   Status status = CallRegress(server_core_.get(), request, &response);
 
  348   EXPECT_EQ(status.code(), error::INVALID_ARGUMENT);
 
  349   EXPECT_THAT(status.message(), ::testing::HasSubstr(
"Input is empty"));
 
  352 TEST_F(TfrtRegressorTest, InvalidFunctionName) {
 
  353   RegressionResponse response;
 
  354   std::unique_ptr<test_util::MockSavedModel> saved_model(
 
  355       (
new test_util::MockSavedModel()));
 
  356   EXPECT_CALL(*saved_model, GetFunctionMetadata(_))
 
  358       .WillRepeatedly(Return(std::nullopt));
 
  359   auto status = RunRegress(tfrt::SavedModel::RunOptions(), kTestModelVersion,
 
  360                            saved_model.get(), request_, &response);
 
  361   EXPECT_EQ(status.code(), absl::StatusCode::kFailedPrecondition);
 
  362   EXPECT_THAT(status.message(), HasSubstr(
"not found"));
 
  365 TEST_F(TfrtRegressorTest, InvalidFunctionUnmatchedInputSize) {
 
  366   RegressionResponse response;
 
  367   std::unique_ptr<test_util::MockSavedModel> saved_model(
 
  368       (
new test_util::MockSavedModel()));
 
  369   tfrt::internal::Signature signature;
 
  370   signature.input_names = {kRegressInputs, 
"wrong input"};
 
  371   signature.output_names = {kRegressOutputs};
 
  372   tfrt::FunctionMetadata function_metadata(&signature);
 
  373   EXPECT_CALL(*saved_model, GetFunctionMetadata(_))
 
  375       .WillRepeatedly(Return(function_metadata));
 
  376   auto status = RunRegress(tfrt::SavedModel::RunOptions(), kTestModelVersion,
 
  377                            saved_model.get(), request_, &response);
 
  378   EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
 
  379   EXPECT_THAT(status.message(), HasSubstr(
"Expected one input Tensor."));
 
  382 TEST_F(TfrtRegressorTest, InvalidFunctionUnmatchedOutputSize) {
 
  383   RegressionResponse response;
 
  384   std::unique_ptr<test_util::MockSavedModel> saved_model(
 
  385       (
new test_util::MockSavedModel()));
 
  386   tfrt::internal::Signature signature;
 
  387   signature.input_names = {kRegressInputs};
 
  388   signature.output_names = {kRegressOutputs, 
"wrong output"};
 
  389   tfrt::FunctionMetadata function_metadata(&signature);
 
  390   EXPECT_CALL(*saved_model, GetFunctionMetadata(_))
 
  392       .WillRepeatedly(Return(function_metadata));
 
  393   auto status = RunRegress(tfrt::SavedModel::RunOptions(), kTestModelVersion,
 
  394                            saved_model.get(), request_, &response);
 
  395   EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
 
  396   EXPECT_THAT(status.message(), HasSubstr(
"Expected one output Tensor."));
 
  399 TEST_F(TfrtRegressorTest, InvalidFunctionInvalidInputName) {
 
  400   RegressionResponse response;
 
  401   std::unique_ptr<test_util::MockSavedModel> saved_model(
 
  402       (
new test_util::MockSavedModel()));
 
  403   tfrt::internal::Signature signature;
 
  404   signature.input_names = {
"wrong input"};
 
  405   signature.output_names = {kRegressOutputs};
 
  406   tfrt::FunctionMetadata function_metadata(&signature);
 
  407   EXPECT_CALL(*saved_model, GetFunctionMetadata(_))
 
  409       .WillRepeatedly(Return(function_metadata));
 
  410   auto status = RunRegress(tfrt::SavedModel::RunOptions(), kTestModelVersion,
 
  411                            saved_model.get(), request_, &response);
 
  412   EXPECT_EQ(status.code(), absl::StatusCode::kFailedPrecondition);
 
  413   EXPECT_THAT(status.message(),
 
  414               HasSubstr(
"No regression inputs found in function's metadata"));
 
  417 TEST_F(TfrtRegressorTest, InvalidFunctionInvalidOutputName) {
 
  418   RegressionResponse response;
 
  419   std::unique_ptr<test_util::MockSavedModel> saved_model(
 
  420       (
new test_util::MockSavedModel()));
 
  421   tfrt::internal::Signature signature;
 
  422   signature.input_names = {kRegressInputs};
 
  423   signature.output_names = {
"wrong output"};
 
  424   tfrt::FunctionMetadata function_metadata(&signature);
 
  425   EXPECT_CALL(*saved_model, GetFunctionMetadata(_))
 
  427       .WillRepeatedly(Return(function_metadata));
 
  428   auto status = RunRegress(tfrt::SavedModel::RunOptions(), kTestModelVersion,
 
  429                            saved_model.get(), request_, &response);
 
  430   EXPECT_EQ(status.code(), absl::StatusCode::kFailedPrecondition);
 
  431   EXPECT_THAT(status.message(),
 
  432               HasSubstr(
"No regression outputs found in function's metadata"));
 
  435 TEST_F(TfrtRegressorTest, RunsFails) {
 
  436   RegressionResponse response;
 
  437   std::unique_ptr<test_util::MockSavedModel> saved_model(
 
  438       (
new test_util::MockSavedModel()));
 
  439   tfrt::internal::Signature signature;
 
  440   signature.input_names = {kRegressInputs};
 
  441   signature.output_names = {kRegressOutputs};
 
  442   tfrt::FunctionMetadata function_metadata(&signature);
 
  443   EXPECT_CALL(*saved_model, GetFunctionMetadata(_))
 
  445       .WillRepeatedly(Return(function_metadata));
 
  446   EXPECT_CALL(*saved_model,
 
  447               Run(_, _, ::testing::An<absl::Span<const Tensor>>(), _))
 
  449       .WillRepeatedly(Return(errors::InvalidArgument(
"test error")));
 
  450   auto status = RunRegress(tfrt::SavedModel::RunOptions(), kTestModelVersion,
 
  451                            saved_model.get(), request_, &response);
 
  452   EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
 
  453   EXPECT_THAT(status.message(), HasSubstr(
"test error"));
 
  456 TEST_F(TfrtRegressorTest, UnexpectedOutputTensorNumber) {
 
  457   RegressionResponse response;
 
  458   std::unique_ptr<test_util::MockSavedModel> saved_model(
 
  459       (
new test_util::MockSavedModel()));
 
  460   tfrt::internal::Signature signature;
 
  461   signature.input_names = {kRegressInputs};
 
  462   signature.output_names = {kRegressOutputs};
 
  463   tfrt::FunctionMetadata function_metadata(&signature);
 
  464   EXPECT_CALL(*saved_model, GetFunctionMetadata(_))
 
  466       .WillRepeatedly(Return(function_metadata));
 
  468   EXPECT_CALL(*saved_model,
 
  469               Run(_, _, ::testing::An<absl::Span<const Tensor>>(), _))
 
  472           DoAll(WithArgs<3>([&](std::vector<Tensor>* output_tensors) {
 
  473                   output_tensors->push_back(output);
 
  474                   output_tensors->push_back(output);
 
  476                 Return(absl::OkStatus())));
 
  477   auto status = RunRegress(tfrt::SavedModel::RunOptions(), kTestModelVersion,
 
  478                            saved_model.get(), request_, &response);
 
  479   EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
 
  480   EXPECT_THAT(status.message(),
 
  481               HasSubstr(
"Expected output_tensors and output_tensor_names to " 
  482                         "have the same size."));
 
  485 TEST_F(TfrtRegressorTest, UnexpectedOutputTensorShape) {
 
  486   RegressionResponse response;
 
  487   std::unique_ptr<test_util::MockSavedModel> saved_model(
 
  488       (
new test_util::MockSavedModel()));
 
  489   tfrt::internal::Signature signature;
 
  490   signature.input_names = {kRegressInputs};
 
  491   signature.output_names = {kRegressOutputs};
 
  492   tfrt::FunctionMetadata function_metadata(&signature);
 
  493   EXPECT_CALL(*saved_model, GetFunctionMetadata(_))
 
  495       .WillRepeatedly(Return(function_metadata));
 
  496   Tensor output(DT_FLOAT, TensorShape({1, 1, 1}));
 
  497   EXPECT_CALL(*saved_model,
 
  498               Run(_, _, ::testing::An<absl::Span<const Tensor>>(), _))
 
  501           DoAll(WithArgs<3>([&](std::vector<Tensor>* output_tensors) {
 
  502                   output_tensors->push_back(output);
 
  504                 Return(absl::OkStatus())));
 
  505   auto status = RunRegress(tfrt::SavedModel::RunOptions(), kTestModelVersion,
 
  506                            saved_model.get(), request_, &response);
 
  507   EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
 
  508   EXPECT_THAT(status.message(),
 
  509               HasSubstr(
"Expected output Tensor shape to be either"));
 
  512 TEST_F(TfrtRegressorTest, UnexpectedOutputTensorSize) {
 
  513   RegressionResponse response;
 
  514   std::unique_ptr<test_util::MockSavedModel> saved_model(
 
  515       (
new test_util::MockSavedModel()));
 
  516   tfrt::internal::Signature signature;
 
  517   signature.input_names = {kRegressInputs};
 
  518   signature.output_names = {kRegressOutputs};
 
  519   tfrt::FunctionMetadata function_metadata(&signature);
 
  520   EXPECT_CALL(*saved_model, GetFunctionMetadata(_))
 
  522       .WillRepeatedly(Return(function_metadata));
 
  523   Tensor output(DT_FLOAT, TensorShape({3}));
 
  524   EXPECT_CALL(*saved_model,
 
  525               Run(_, _, ::testing::An<absl::Span<const Tensor>>(), _))
 
  528           DoAll(WithArgs<3>([&](std::vector<Tensor>* output_tensors) {
 
  529                   output_tensors->push_back(output);
 
  531                 Return(absl::OkStatus())));
 
  532   auto status = RunRegress(tfrt::SavedModel::RunOptions(), kTestModelVersion,
 
  533                            saved_model.get(), request_, &response);
 
  534   EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
 
  535   EXPECT_THAT(status.message(),
 
  536               HasSubstr(
"Input batch size did not match output batch size"));
 
  539 TEST_F(TfrtRegressorTest, UnexpectedOutputTensorType) {
 
  540   RegressionResponse response;
 
  541   std::unique_ptr<test_util::MockSavedModel> saved_model(
 
  542       (
new test_util::MockSavedModel()));
 
  543   tfrt::internal::Signature signature;
 
  544   signature.input_names = {kRegressInputs};
 
  545   signature.output_names = {kRegressOutputs};
 
  546   tfrt::FunctionMetadata function_metadata(&signature);
 
  547   EXPECT_CALL(*saved_model, GetFunctionMetadata(_))
 
  549       .WillRepeatedly(Return(function_metadata));
 
  550   Tensor output(DT_STRING, TensorShape({1}));
 
  551   EXPECT_CALL(*saved_model,
 
  552               Run(_, _, ::testing::An<absl::Span<const Tensor>>(), _))
 
  555           DoAll(WithArgs<3>([&](std::vector<Tensor>* output_tensors) {
 
  556                   output_tensors->push_back(output);
 
  558                 Return(absl::OkStatus())));
 
  559   auto status = RunRegress(tfrt::SavedModel::RunOptions(), kTestModelVersion,
 
  560                            saved_model.get(), request_, &response);
 
  561   EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
 
  562   EXPECT_THAT(status.message(),
 
  563               HasSubstr(
"Expected output Tensor of DT_FLOAT."));
 
static Status Create(Options options, std::unique_ptr< ServerCore > *core)