16 #include "tensorflow_serving/model_servers/server_core.h"
20 #include <unordered_map>
24 #include "google/protobuf/any.pb.h"
25 #include "absl/status/status.h"
26 #include "absl/strings/strip.h"
27 #include "tensorflow/cc/saved_model/tag_constants.h"
28 #include "xla/tsl/lib/core/status_test_util.h"
29 #include "tensorflow/core/lib/core/status.h"
30 #include "tensorflow/core/lib/core/status_test_util.h"
31 #include "tensorflow/core/lib/io/path.h"
32 #include "tensorflow/core/lib/random/random.h"
33 #include "tensorflow/core/lib/strings/stringprintf.h"
34 #include "tensorflow/core/platform/path.h"
35 #include "tensorflow/core/platform/types.h"
36 #include "tensorflow/core/protobuf/error_codes.pb.h"
37 #include "tensorflow_serving/apis/model.pb.h"
38 #include "tensorflow_serving/apis/predict.pb.h"
39 #include "tensorflow_serving/core/request_logger.h"
40 #include "tensorflow_serving/core/servable_handle.h"
41 #include "tensorflow_serving/core/servable_id.h"
42 #include "tensorflow_serving/core/servable_state.h"
43 #include "tensorflow_serving/core/test_util/availability_test_util.h"
44 #include "tensorflow_serving/core/test_util/fake_loader_source_adapter.pb.h"
45 #include "tensorflow_serving/core/test_util/fake_log_collector.h"
46 #include "tensorflow_serving/core/test_util/mock_prediction_stream_logger.h"
47 #include "tensorflow_serving/core/test_util/mock_request_logger.h"
48 #include "tensorflow_serving/model_servers/model_platform_types.h"
49 #include "tensorflow_serving/model_servers/test_util/server_core_test_util.h"
50 #include "tensorflow_serving/model_servers/test_util/storage_path_error_injecting_source_adapter.h"
51 #include "tensorflow_serving/model_servers/test_util/storage_path_error_injecting_source_adapter.pb.h"
52 #include "tensorflow_serving/test_util/test_util.h"
53 #include "tensorflow_serving/util/oss_or_google.h"
55 namespace tensorflow {
59 using test_util::MockPredictionStreamLogger;
60 using test_util::ServerCoreTest;
62 using ::testing::Invoke;
63 using ::testing::MockFunction;
64 using ::testing::NiceMock;
65 using ::testing::Pair;
66 using ::testing::UnorderedElementsAre;
68 TEST_P(ServerCoreTest, PreLoadHook) {
69 std::unique_ptr<ServerCore> server_core;
70 ServerCore::Options options = GetDefaultOptions();
71 MockFunction<void(
const ServableId&)> mock_pre_load_hook;
72 options.pre_load_hook = mock_pre_load_hook.AsStdFunction();
73 options.model_server_config = GetTestModelServerConfigForFakePlatform();
75 const ServableId expected_id = {test_util::kTestModelName,
76 test_util::kTestModelVersion};
77 EXPECT_CALL(mock_pre_load_hook, Call(expected_id));
81 TEST_P(ServerCoreTest, CreateWaitsTillModelsAvailable) {
82 std::unique_ptr<ServerCore> server_core;
83 TF_ASSERT_OK(CreateServerCore(GetTestModelServerConfigForFakePlatform(),
86 const std::vector<ServableId> available_servables =
87 server_core->ListAvailableServableIds();
88 ASSERT_EQ(available_servables.size(), 1);
89 const ServableId expected_id = {test_util::kTestModelName,
90 test_util::kTestModelVersion};
91 EXPECT_EQ(available_servables.at(0), expected_id);
94 model_spec.set_name(test_util::kTestModelName);
95 model_spec.mutable_version()->set_value(test_util::kTestModelVersion);
96 ServableHandle<string> servable_handle;
98 server_core->GetServableHandle<
string>(model_spec, &servable_handle));
99 EXPECT_EQ(servable_handle.id(), expected_id);
102 const auto servable_map =
103 server_core->servable_state_monitor()->GetAllServableStates();
104 auto it_servable = servable_map.find(test_util::kTestModelName);
105 ASSERT_NE(it_servable, servable_map.end());
106 ASSERT_THAT(it_servable->second,
107 UnorderedElementsAre(Pair(test_util::kTestModelVersion, _)));
108 const auto state_and_time =
109 it_servable->second.at(test_util::kTestModelVersion);
110 EXPECT_TRUE(state_and_time.state.health.ok());
111 EXPECT_EQ(state_and_time.state.manager_state,
112 ServableState::ManagerState::kAvailable);
115 TEST_P(ServerCoreTest, ReloadConfigWaitsTillModelsAvailable) {
117 std::unique_ptr<ServerCore> server_core;
118 TF_ASSERT_OK(CreateServerCore(ModelServerConfig(), &server_core));
122 server_core->ReloadConfig(GetTestModelServerConfigForFakePlatform()));
124 const std::vector<ServableId> available_servables =
125 server_core->ListAvailableServableIds();
126 ASSERT_EQ(available_servables.size(), 1);
127 const ServableId expected_id = {test_util::kTestModelName,
128 test_util::kTestModelVersion};
129 EXPECT_EQ(available_servables.at(0), expected_id);
132 TEST_P(ServerCoreTest, ReloadConfigUnloadsModels) {
133 const ModelServerConfig nonempty_config =
134 GetTestModelServerConfigForFakePlatform();
135 ModelServerConfig empty_config;
136 empty_config.mutable_model_config_list();
137 const ServableId servable_id = {test_util::kTestModelName,
138 test_util::kTestModelVersion};
140 std::unique_ptr<ServerCore> server_core;
141 TF_ASSERT_OK(CreateServerCore(nonempty_config, &server_core));
142 ASSERT_FALSE(server_core->ListAvailableServableIds().empty());
144 TF_ASSERT_OK(server_core->ReloadConfig(empty_config));
146 test_util::WaitUntilServableManagerStateIsOneOf(
147 *server_core->servable_state_monitor(), servable_id,
148 {ServableState::ManagerState::kEnd});
150 const auto servable_map =
151 server_core->servable_state_monitor()->GetAllServableStates();
152 auto it_servable = servable_map.find(test_util::kTestModelName);
153 ASSERT_NE(it_servable, servable_map.end());
154 ASSERT_THAT(it_servable->second,
155 UnorderedElementsAre(Pair(test_util::kTestModelVersion, _)));
156 const auto state_and_time =
157 it_servable->second.at(test_util::kTestModelVersion);
158 ASSERT_EQ(state_and_time.state.manager_state,
159 ServableState::ManagerState::kEnd);
162 TEST_P(ServerCoreTest, ReloadConfigHandlesLoadingAPreviouslyUnloadedModel) {
163 ModelServerConfig empty_config;
164 empty_config.mutable_model_config_list();
165 const ModelServerConfig nonempty_config =
166 GetTestModelServerConfigForFakePlatform();
167 const ServableId servable_id = {test_util::kTestModelName,
168 test_util::kTestModelVersion};
171 std::unique_ptr<ServerCore> server_core;
172 TF_ASSERT_OK(CreateServerCore(nonempty_config, &server_core));
173 TF_ASSERT_OK(server_core->ReloadConfig(empty_config));
175 test_util::WaitUntilServableManagerStateIsOneOf(
176 *server_core->servable_state_monitor(), servable_id,
177 {ServableState::ManagerState::kEnd});
180 TF_ASSERT_OK(server_core->ReloadConfig(nonempty_config));
181 const std::vector<ServableId> available_servables =
182 server_core->ListAvailableServableIds();
183 ASSERT_EQ(available_servables.size(), 1);
184 const ServableId expected_id = {test_util::kTestModelName,
185 test_util::kTestModelVersion};
186 EXPECT_EQ(available_servables.at(0), expected_id);
189 TEST_P(ServerCoreTest, ReloadConfigChangeModelBasePath) {
193 const ModelServerConfig one_version_config =
194 GetTestModelServerConfigForFakePlatform();
195 ModelServerConfig two_version_config =
196 GetTestModelServerConfigForFakePlatform();
197 SwitchToHalfPlusTwoWith2Versions(&two_version_config);
200 std::unique_ptr<ServerCore> server_core;
201 TF_ASSERT_OK(CreateServerCore(one_version_config, &server_core));
202 std::vector<ServableId> available_servables =
203 server_core->ListAvailableServableIds();
204 ASSERT_EQ(1, available_servables.size());
205 EXPECT_EQ(test_util::kTestModelVersion, available_servables.at(0).version);
208 TF_ASSERT_OK(server_core->ReloadConfig(two_version_config));
212 Env::Default()->SleepForMicroseconds(10 * 1000);
213 available_servables = server_core->ListAvailableServableIds();
214 }
while (available_servables.empty() ||
215 available_servables.at(0).version !=
216 test_util::kTestModelLargerVersion);
219 TF_ASSERT_OK(server_core->ReloadConfig(one_version_config));
223 Env::Default()->SleepForMicroseconds(10 * 1000);
224 available_servables = server_core->ListAvailableServableIds();
225 }
while (available_servables.empty() ||
226 available_servables.at(0).version != test_util::kTestModelVersion);
229 class RelativePathsServerCoreTest :
public ServerCoreTest {
234 ModelServerConfig GetTestModelServerConfigWithRelativePath(
235 string* optional_config_list_root_dir =
nullptr) {
236 using ::tensorflow::io::Basename;
237 using ::tensorflow::io::Dirname;
239 ModelServerConfig result = GetTestModelServerConfigForFakePlatform();
240 const string model_name = result.model_config_list().config(0).name();
242 ModelConfig& relative =
243 *result.mutable_model_config_list()->mutable_config(0);
244 relative.set_name(strings::StrCat(model_name,
"_relative"));
245 const string dirname(Dirname(relative.base_path()));
246 const string basename(Basename(relative.base_path()));
247 CHECK(!dirname.empty());
248 CHECK(!basename.empty());
249 relative.set_base_path(basename);
251 if (optional_config_list_root_dir) {
252 *optional_config_list_root_dir = dirname;
259 TEST_P(RelativePathsServerCoreTest, AbsolutePathSucceeds) {
260 std::unique_ptr<ServerCore> server_core;
261 ModelServerConfig absolute = GetTestModelServerConfigForFakePlatform();
262 TF_ASSERT_OK(CreateServerCore(absolute, &server_core));
265 TEST_P(RelativePathsServerCoreTest, RelativePathFails) {
266 std::unique_ptr<ServerCore> server_core;
267 ModelServerConfig relative = GetTestModelServerConfigWithRelativePath();
268 EXPECT_EQ(error::INVALID_ARGUMENT,
269 CreateServerCore(relative, &server_core).code());
272 TEST_P(RelativePathsServerCoreTest,
273 AbsoluteAndRelativePathsWithOptionsSucceed) {
274 std::unique_ptr<ServerCore> server_core;
275 ModelServerConfig absolute_and_relative;
276 ModelServerConfig absolute = GetTestModelServerConfigForFakePlatform();
277 ServerCore::Options options = GetDefaultOptions();
279 string model_config_list_root_dir;
280 ModelServerConfig relative =
281 GetTestModelServerConfigWithRelativePath(&model_config_list_root_dir);
284 CHECK_GT(relative.model_config_list().config_size(), 0);
285 CHECK_GT(absolute.model_config_list().config_size(), 0);
286 *absolute_and_relative.mutable_model_config_list()->add_config() =
287 absolute.model_config_list().config(0);
288 *absolute_and_relative.mutable_model_config_list()->add_config() =
289 relative.model_config_list().config(0);
290 options.model_config_list_root_dir = std::move(model_config_list_root_dir);
292 TF_ASSERT_OK(CreateServerCore(absolute_and_relative, std::move(options),
296 TEST_P(RelativePathsServerCoreTest, AbsolutePathWithEmptyPathFails) {
297 std::unique_ptr<ServerCore> server_core;
298 ModelServerConfig absolute = GetTestModelServerConfigForFakePlatform();
299 ServerCore::Options options = GetDefaultOptions();
300 options.model_config_list_root_dir =
"";
302 error::INVALID_ARGUMENT,
303 CreateServerCore(absolute, std::move(options), &server_core).code());
306 TEST_P(RelativePathsServerCoreTest, RelativePathWithOptionsSucceeds) {
307 std::unique_ptr<ServerCore> server_core;
308 ServerCore::Options options = GetDefaultOptions();
309 string model_config_list_root_dir;
310 ModelServerConfig relative =
311 GetTestModelServerConfigWithRelativePath(&model_config_list_root_dir);
312 options.model_config_list_root_dir = std::move(model_config_list_root_dir);
313 TF_ASSERT_OK(CreateServerCore(relative, std::move(options), &server_core));
316 TEST_P(RelativePathsServerCoreTest, MixedAbsoluteRelativeFails) {
317 std::unique_ptr<ServerCore> server_core;
318 ModelServerConfig mixed = GetTestModelServerConfigForFakePlatform();
319 const ModelServerConfig relative = GetTestModelServerConfigWithRelativePath();
320 *mixed.mutable_model_config_list()->add_config() =
321 relative.model_config_list().config(0);
322 EXPECT_EQ(error::INVALID_ARGUMENT,
323 CreateServerCore(mixed, &server_core).code());
326 TEST_P(ServerCoreTest, ErroringModel) {
327 ServerCore::Options options = GetDefaultOptions();
328 test_util::StoragePathErrorInjectingSourceAdapterConfig source_adapter_config;
329 source_adapter_config.set_error_message(
"injected error");
330 ::google::protobuf::Any source_adapter_config_any;
331 source_adapter_config_any.PackFrom(source_adapter_config);
332 (*(*options.platform_config_map
333 .mutable_platform_configs())[test_util::kFakePlatform]
334 .mutable_source_adapter_config()) = source_adapter_config_any;
335 options.model_server_config = GetTestModelServerConfigForFakePlatform();
336 std::unique_ptr<ServerCore> server_core;
338 EXPECT_FALSE(status.ok());
339 EXPECT_THAT(status.ToString(),
340 ::testing::HasSubstr(
"1 servable(s) did not become available"));
343 const auto servable_map =
344 server_core->servable_state_monitor()->GetAllServableStates();
345 auto it_servable = servable_map.find(test_util::kTestModelName);
346 ASSERT_NE(it_servable, servable_map.end());
347 ASSERT_THAT(it_servable->second,
348 UnorderedElementsAre(Pair(test_util::kTestModelVersion, _)));
349 const auto state_and_time =
350 it_servable->second.at(test_util::kTestModelVersion);
351 EXPECT_EQ(state_and_time.state.health.code(), absl::StatusCode::kCancelled);
352 EXPECT_THAT(state_and_time.state.health.ToString(),
353 ::testing::HasSubstr(
"injected error"));
354 EXPECT_EQ(state_and_time.state.manager_state,
355 ServableState::ManagerState::kEnd);
358 TEST_P(ServerCoreTest, IllegalReconfigurationToCustomConfig) {
360 std::unique_ptr<ServerCore> server_core;
361 TF_ASSERT_OK(CreateServerCore(GetTestModelServerConfigForFakePlatform(),
366 ModelServerConfig config;
367 config.mutable_custom_model_config();
368 EXPECT_THAT(server_core->ReloadConfig(config).ToString(),
369 ::testing::HasSubstr(
"Cannot transition to requested config"));
372 TEST_P(ServerCoreTest, IllegalReconfigurationFromCustomConfig) {
374 std::unique_ptr<ServerCore> server_core;
375 ModelServerConfig config;
376 config.mutable_custom_model_config();
377 TF_ASSERT_OK(CreateServerCore(config, &server_core));
382 server_core->ReloadConfig(GetTestModelServerConfigForFakePlatform())
384 ::testing::HasSubstr(
"Cannot transition to requested config"));
387 TEST_P(ServerCoreTest, IllegalConfigModelTypeAndPlatformSet) {
389 std::unique_ptr<ServerCore> server_core;
390 ModelServerConfig config = GetTestModelServerConfigForFakePlatform();
391 config.mutable_model_config_list()->mutable_config(0)->set_model_type(
392 ModelType::TENSORFLOW);
393 EXPECT_THAT(CreateServerCore(config, &server_core).ToString(),
394 ::testing::HasSubstr(
"Illegal setting both"));
397 TEST_P(ServerCoreTest, DeprecatedModelTypeConfig) {
399 std::unique_ptr<ServerCore> server_core;
400 ModelServerConfig config = GetTestModelServerConfigForTensorflowPlatform();
401 config.mutable_model_config_list()->mutable_config(0)->set_model_platform(
"");
402 config.mutable_model_config_list()->mutable_config(0)->set_model_type(
403 ModelType::TENSORFLOW);
404 TF_ASSERT_OK(CreateServerCore(config, &server_core));
406 const std::vector<ServableId> available_servables =
407 server_core->ListAvailableServableIds();
408 ASSERT_EQ(available_servables.size(), 1);
409 const ServableId expected_id = {test_util::kTestModelName,
410 test_util::kTestModelVersion};
411 EXPECT_EQ(available_servables.at(0), expected_id);
414 TEST_P(ServerCoreTest, DuplicateModelNameInConfig) {
415 std::unique_ptr<ServerCore> server_core;
416 ModelServerConfig config = GetTestModelServerConfigForTensorflowPlatform();
417 *config.mutable_model_config_list()->add_config() =
418 config.model_config_list().config(0);
419 EXPECT_FALSE(CreateServerCore(config, &server_core).ok());
422 TEST_P(ServerCoreTest, UnknownModelPlatform) {
423 std::unique_ptr<ServerCore> server_core;
424 ModelServerConfig config = GetTestModelServerConfigForTensorflowPlatform();
425 config.mutable_model_config_list()->mutable_config(0)->set_model_platform(
426 "not_a_known_platform");
427 EXPECT_FALSE(CreateServerCore(config, &server_core).ok());
437 string ModelNameForPlatform(
const string& platform) {
438 static std::map<string, string>* platform_to_model_map = [] {
439 return new std::map<string, string>();
441 auto it = platform_to_model_map->find(platform);
442 if (it != platform_to_model_map->end()) {
445 const string random = strings::StrCat(random::New64());
446 const string model_name =
447 strings::StrCat(
"model_", random,
"_for_", platform);
448 (*platform_to_model_map)[platform] = model_name;
454 ModelSpec ModelSpecForPlatform(
const string& platform) {
456 spec.set_name(ModelNameForPlatform(platform));
457 spec.mutable_version()->set_value(0);
463 ModelConfig ModelConfigForPlatform(
const string& root_path,
464 const string& platform) {
465 const string model_name = ModelNameForPlatform(platform);
467 config.set_name(model_name);
468 config.set_base_path(io::JoinPath(root_path, model_name));
469 config.set_model_platform(platform);
474 void CreateModelDir(
const ModelConfig& model_config,
int version) {
475 TF_CHECK_OK(Env::Default()->CreateDir(model_config.base_path()));
476 const string version_str = strings::StrCat(version);
477 TF_CHECK_OK(Env::Default()->CreateDir(
478 io::JoinPath(model_config.base_path(), version_str)));
483 void CreateFakePlatform(
const string& platform,
484 PlatformConfigMap* platform_config_map) {
485 test_util::FakeLoaderSourceAdapterConfig source_adapter_config;
486 source_adapter_config.set_suffix(strings::StrCat(
"suffix_for_", platform));
487 ::google::protobuf::Any source_adapter_config_any;
488 source_adapter_config_any.PackFrom(source_adapter_config);
489 (*(*platform_config_map->mutable_platform_configs())[platform]
490 .mutable_source_adapter_config()) = source_adapter_config_any;
494 string ServableDataForPlatform(
const string& root_path,
const string& platform,
496 const string version_str = strings::StrCat(version);
497 return io::JoinPath(root_path, ModelNameForPlatform(platform), version_str,
498 strings::StrCat(
"suffix_for_", platform));
501 TEST_P(ServerCoreTest, MultiplePlatforms) {
502 const string root_path =
503 io::JoinPath(testing::TmpDir(),
504 strings::StrCat(
"MultiplePlatforms_", GetNameForTestCase()));
505 TF_ASSERT_OK(Env::Default()->CreateDir(root_path));
508 ServerCore::Options options = GetDefaultOptions();
509 options.platform_config_map.Clear();
510 const std::vector<string> platforms = {
"platform_0",
"platform_1"};
511 for (
const string& platform : platforms) {
512 CreateFakePlatform(platform, &options.platform_config_map);
513 const ModelConfig model_config =
514 ModelConfigForPlatform(root_path, platform);
515 *options.model_server_config.mutable_model_config_list()->add_config() =
517 CreateModelDir(model_config, 0 );
519 std::unique_ptr<ServerCore> server_core;
523 for (
const string& platform : platforms) {
524 ServableHandle<string> servable_handle;
525 TF_ASSERT_OK(server_core->GetServableHandle<
string>(
526 ModelSpecForPlatform(platform), &servable_handle));
527 const string model_name = ModelNameForPlatform(platform);
528 const auto expected_servable_id = ServableId{model_name, 0};
529 EXPECT_EQ(servable_handle.id(), expected_servable_id);
530 EXPECT_EQ(ServableDataForPlatform(root_path, platform, 0 ),
535 TEST_P(ServerCoreTest, MultiplePlatformsWithConfigChange) {
536 const string root_path = io::JoinPath(
537 testing::TmpDir(), strings::StrCat(
"MultiplePlatformsWithConfigChange_",
538 GetNameForTestCase()));
539 TF_ASSERT_OK(Env::Default()->CreateDir(root_path));
542 ServerCore::Options options = GetDefaultOptions();
543 options.platform_config_map.Clear();
544 const std::vector<string> platforms = {
"platform_0",
"platform_1",
546 std::vector<ModelConfig> models;
547 for (
const string& platform : platforms) {
548 CreateFakePlatform(platform, &options.platform_config_map);
549 const ModelConfig model_config =
550 ModelConfigForPlatform(root_path, platform);
551 models.push_back(model_config);
552 CreateModelDir(model_config, 0 );
555 auto verify_model_loaded = [&root_path](ServerCore* server_core,
556 const string& platform) {
557 ServableHandle<string> servable_handle;
558 TF_ASSERT_OK(server_core->GetServableHandle<
string>(
559 ModelSpecForPlatform(platform), &servable_handle));
560 const string model_name = ModelNameForPlatform(platform);
561 const auto expected_servable_id = ServableId{model_name, 0};
562 EXPECT_EQ(servable_handle.id(), expected_servable_id);
563 EXPECT_EQ(ServableDataForPlatform(root_path, platform, 0 ),
566 auto verify_model_not_loaded = [](ServerCore* server_core,
567 const string& platform) {
568 ServableHandle<string> servable_handle;
569 EXPECT_FALSE(server_core
570 ->GetServableHandle<string>(ModelSpecForPlatform(platform),
576 ModelServerConfig* initial_model_config = &options.model_server_config;
577 (*initial_model_config->mutable_model_config_list()->add_config()) =
579 (*initial_model_config->mutable_model_config_list()->add_config()) =
581 std::unique_ptr<ServerCore> server_core;
583 verify_model_loaded(server_core.get(), platforms[0]);
584 verify_model_loaded(server_core.get(), platforms[1]);
585 verify_model_not_loaded(server_core.get(), platforms[2]);
588 ModelServerConfig new_model_config;
589 (*new_model_config.mutable_model_config_list()->add_config()) = models[1];
590 (*new_model_config.mutable_model_config_list()->add_config()) = models[2];
591 TF_ASSERT_OK(server_core->ReloadConfig(new_model_config));
592 verify_model_not_loaded(server_core.get(), platforms[0]);
593 verify_model_loaded(server_core.get(), platforms[1]);
594 verify_model_loaded(server_core.get(), platforms[2]);
597 TEST_P(ServerCoreTest, IllegalToChangeModelPlatform) {
598 const string root_path = io::JoinPath(
600 strings::StrCat(
"IllegalToChangeModelPlatform_", GetNameForTestCase()));
601 TF_ASSERT_OK(Env::Default()->CreateDir(root_path));
603 ServerCore::Options options = GetDefaultOptions();
604 options.platform_config_map.Clear();
605 const std::vector<string> platforms = {
"platform_0",
"platform_1"};
606 for (
const string& platform : platforms) {
607 CreateFakePlatform(platform, &options.platform_config_map);
611 ModelServerConfig initial_config;
612 const ModelConfig model_config =
613 ModelConfigForPlatform(root_path, platforms[0]);
614 *initial_config.mutable_model_config_list()->add_config() = model_config;
615 CreateModelDir(model_config, 0 );
617 options.model_server_config = initial_config;
618 std::unique_ptr<ServerCore> server_core;
622 ModelServerConfig new_config = initial_config;
623 new_config.mutable_model_config_list()->mutable_config(0)->set_model_platform(
625 const Status reconfigure_status = server_core->ReloadConfig(new_config);
626 EXPECT_FALSE(reconfigure_status.ok());
627 EXPECT_THAT(reconfigure_status.ToString(),
628 ::testing::HasSubstr(
"Illegal to change a model's platform"));
631 TEST_P(ServerCoreTest, RequestLoggingOff) {
633 std::unique_ptr<ServerCore> server_core;
634 const ModelServerConfig config =
635 GetTestModelServerConfigForTensorflowPlatform();
636 TF_ASSERT_OK(CreateServerCore(config, &server_core));
639 server_core->Log(PredictRequest(), PredictResponse(), LogMetadata()));
641 server_core->StartLoggingStream<PredictRequest, PredictResponse>(
643 []() {
return std::make_unique<MockPredictionStreamLogger>(); });
644 EXPECT_EQ(logger,
nullptr);
647 TEST_P(ServerCoreTest, RequestLoggingOn) {
648 std::unordered_map<string, FakeLogCollector*> log_collector_map;
649 ServerCore::Options options = GetDefaultOptions();
650 TF_CHECK_OK(ServerRequestLogger::Create(
651 [&](
const LoggingConfig& logging_config,
652 std::shared_ptr<RequestLogger>*
const request_logger) {
653 const string& filename_prefix =
654 logging_config.log_collector_config().filename_prefix();
655 log_collector_map[filename_prefix] =
new FakeLogCollector();
656 const std::vector<string>& tags = {kSavedModelTagServe};
657 auto mock_request_logger = std::shared_ptr<NiceMock<MockRequestLogger>>(
658 new NiceMock<MockRequestLogger>(
659 logging_config, tags, log_collector_map[filename_prefix]));
660 ON_CALL(*mock_request_logger, CreateLogMessage(_, _, _, _))
661 .WillByDefault(Invoke([&](
const google::protobuf::Message& actual_request,
662 const google::protobuf::Message& actual_response,
663 const LogMetadata& actual_log_metadata,
664 std::unique_ptr<google::protobuf::Message>* log) {
665 *log = std::unique_ptr<google::protobuf::Any>(
666 new google::protobuf::Any());
667 return absl::OkStatus();
669 *request_logger = std::move(mock_request_logger);
670 return absl::OkStatus();
672 &options.server_request_logger));
676 LogCollectorConfig log_collector_config;
677 log_collector_config.set_type(
"");
678 log_collector_config.set_filename_prefix(test_util::kTestModelName);
679 LoggingConfig logging_config;
680 *logging_config.mutable_log_collector_config() = log_collector_config;
681 logging_config.mutable_sampling_config()->set_sampling_rate(1.0);
683 ModelServerConfig model_server_config =
684 GetTestModelServerConfigForTensorflowPlatform();
685 *model_server_config.mutable_model_config_list()
687 ->mutable_logging_config() = logging_config;
688 options.model_server_config = model_server_config;
690 std::unique_ptr<ServerCore> server_core;
694 LogMetadata log_metadata0;
695 auto*
const model_spec0 = log_metadata0.mutable_model_spec();
696 model_spec0->set_name(test_util::kTestModelName);
698 server_core->Log(PredictRequest(), PredictResponse(), log_metadata0));
699 ASSERT_EQ(1, log_collector_map.size());
700 EXPECT_EQ(1, log_collector_map[test_util::kTestModelName]->collect_count());
703 auto* logger_ptr =
new MockPredictionStreamLogger();
705 server_core->StartLoggingStream<PredictRequest, PredictResponse>(
707 [logger_ptr]() {
return absl::WrapUnique(logger_ptr); });
708 EXPECT_CALL(*logger_ptr, CreateLogMessage(_, _))
709 .WillOnce(Invoke([](
const LogMetadata& log_metadata,
710 std::unique_ptr<google::protobuf::Message>* log) {
711 *log = std::make_unique<google::protobuf::Any>();
712 return absl::OkStatus();
714 TF_ASSERT_OK(logger->LogMessage());
715 ASSERT_EQ(1, log_collector_map.size());
716 EXPECT_EQ(2, log_collector_map[test_util::kTestModelName]->collect_count());
719 TEST_P(ServerCoreTest, ModelSpecMultipleVersionsAvailable) {
720 ModelServerConfig two_version_config =
721 GetTestModelServerConfigForFakePlatform();
722 SwitchToHalfPlusTwoWith2Versions(&two_version_config);
723 ServerCore::Options server_core_options = GetDefaultOptions();
724 server_core_options.allow_version_labels =
true;
725 std::unique_ptr<ServerCore> server_core;
726 TF_ASSERT_OK(CreateServerCore(two_version_config,
727 std::move(server_core_options), &server_core));
729 test_util::WaitUntilVersionsAvailable(*server_core->servable_state_monitor(),
730 test_util::kTestModelName,
731 test_util::kAspiredVersions);
735 ModelSpec model_spec;
736 model_spec.set_name(test_util::kTestModelName);
737 ServableHandle<string> servable_handle;
739 server_core->GetServableHandle<
string>(model_spec, &servable_handle));
741 (ServableId{test_util::kTestModelName,
742 test_util::kTestModelLargerVersion }),
743 servable_handle.id());
748 ModelSpec model_spec;
749 model_spec.set_name(test_util::kTestModelName);
750 model_spec.mutable_version()->set_value(test_util::kTestModelVersion);
751 ServableHandle<string> servable_handle;
753 server_core->GetServableHandle<
string>(model_spec, &servable_handle));
755 (ServableId{test_util::kTestModelName, test_util::kTestModelVersion}),
756 servable_handle.id());
760 ASSERT_EQ(1, two_version_config.model_config_list().config().size());
761 test_util::MutateModelConfig(&two_version_config)
762 .SetLabelVersion(
"A", test_util::kTestModelVersion)
763 .SetLabelVersion(
"B", test_util::kTestModelLargerVersion);
764 TF_ASSERT_OK(server_core->ReloadConfig(two_version_config));
768 ModelSpec model_spec;
769 model_spec.set_name(test_util::kTestModelName);
770 model_spec.set_version_label(
"A");
771 ServableHandle<string> servable_handle;
773 server_core->GetServableHandle<
string>(model_spec, &servable_handle));
775 (ServableId{test_util::kTestModelName, test_util::kTestModelVersion}),
776 servable_handle.id());
781 ModelSpec model_spec;
782 model_spec.set_name(test_util::kTestModelName);
783 model_spec.set_version_label(
"B");
784 ServableHandle<string> servable_handle;
786 server_core->GetServableHandle<
string>(model_spec, &servable_handle));
787 EXPECT_EQ((ServableId{test_util::kTestModelName,
788 test_util::kTestModelLargerVersion}),
789 servable_handle.id());
794 ModelSpec model_spec;
795 model_spec.set_name(test_util::kTestModelName);
796 model_spec.set_version_label(
"nonexistent label");
797 ServableHandle<string> servable_handle;
799 server_core->GetServableHandle<
string>(model_spec, &servable_handle);
800 ASSERT_FALSE(status.ok());
801 EXPECT_THAT(status.ToString(),
802 ::testing::HasSubstr(
"Unrecognized servable version label"));
806 TEST_P(ServerCoreTest, AssignLabelToUnavailableVersion) {
807 ModelServerConfig two_version_config =
808 GetTestModelServerConfigForFakePlatform();
809 SwitchToHalfPlusTwoWith2Versions(&two_version_config);
810 ServerCore::Options server_core_options = GetDefaultOptions();
811 server_core_options.allow_version_labels =
true;
812 std::unique_ptr<ServerCore> server_core;
813 TF_ASSERT_OK(CreateServerCore(two_version_config,
814 std::move(server_core_options), &server_core));
817 test_util::WaitUntilVersionsAvailable(*server_core->servable_state_monitor(),
818 test_util::kTestModelName,
819 test_util::kAspiredVersions);
822 ASSERT_EQ(1, two_version_config.model_config_list().config().size());
823 test_util::MutateModelConfig(&two_version_config)
824 .SetLabelVersion(
"nice try", test_util::kTestModelBogusVersion);
825 Status status = server_core->ReloadConfig(two_version_config);
826 ASSERT_FALSE(status.ok());
827 EXPECT_THAT(status.ToString(),
828 ::testing::HasSubstr(
"not currently available for inference"));
831 TEST_P(ServerCoreTest, AssignLabelToUnavailableVersionAllowed) {
832 ModelServerConfig two_version_config =
833 GetTestModelServerConfigForFakePlatform();
834 SwitchToHalfPlusTwoWith2Versions(&two_version_config);
835 ServerCore::Options server_core_options = GetDefaultOptions();
836 server_core_options.allow_version_labels =
true;
837 server_core_options.allow_version_labels_for_unavailable_models =
true;
838 std::unique_ptr<ServerCore> server_core;
839 TF_ASSERT_OK(CreateServerCore(two_version_config,
840 std::move(server_core_options), &server_core));
842 test_util::WaitUntilVersionsAvailable(*server_core->servable_state_monitor(),
843 test_util::kTestModelName,
844 test_util::kAspiredVersions);
847 ASSERT_EQ(1, two_version_config.model_config_list().config().size());
848 test_util::MutateModelConfig(&two_version_config)
849 .SetLabelVersion(
"nice try", test_util::kTestModelBogusVersion);
850 Status status = server_core->ReloadConfig(two_version_config);
851 EXPECT_TRUE(status.ok());
854 TEST_P(ServerCoreTest, AssignExistingLabelToUnavailableVersionDisallowed) {
855 ModelServerConfig two_version_config =
856 GetTestModelServerConfigForFakePlatform();
857 SwitchToHalfPlusTwoWith2Versions(&two_version_config);
858 ServerCore::Options server_core_options = GetDefaultOptions();
859 server_core_options.allow_version_labels =
true;
860 server_core_options.allow_version_labels_for_unavailable_models =
true;
861 std::unique_ptr<ServerCore> server_core;
862 TF_ASSERT_OK(CreateServerCore(two_version_config,
863 std::move(server_core_options), &server_core));
865 test_util::WaitUntilVersionsAvailable(*server_core->servable_state_monitor(),
866 test_util::kTestModelName,
867 test_util::kAspiredVersions);
869 ASSERT_EQ(1, two_version_config.model_config_list().config().size());
870 test_util::MutateModelConfig(&two_version_config)
871 .SetLabelVersion(
"A", test_util::kTestModelVersion)
872 .SetLabelVersion(
"B", test_util::kTestModelLargerVersion);
873 TF_ASSERT_OK(server_core->ReloadConfig(two_version_config));
877 ASSERT_EQ(1, two_version_config.model_config_list().config().size());
878 test_util::MutateModelConfig(&two_version_config)
879 .SetLabelVersion(
"A", test_util::kTestModelBogusVersion);
880 Status status = server_core->ReloadConfig(two_version_config);
881 ASSERT_FALSE(status.ok());
882 EXPECT_THAT(status.ToString(),
883 ::testing::HasSubstr(
"not currently available for inference"));
886 TEST_P(ServerCoreTest, AssignExistingLabelToUnavailableVersionAllowed) {
887 ModelServerConfig two_version_config =
888 GetTestModelServerConfigForFakePlatform();
889 SwitchToHalfPlusTwoWith2Versions(&two_version_config);
890 ServerCore::Options server_core_options = GetDefaultOptions();
891 server_core_options.allow_version_labels =
true;
892 server_core_options.force_allow_any_version_labels_for_unavailable_models =
894 std::unique_ptr<ServerCore> server_core;
895 TF_ASSERT_OK(CreateServerCore(two_version_config,
896 std::move(server_core_options), &server_core));
898 test_util::WaitUntilVersionsAvailable(*server_core->servable_state_monitor(),
899 test_util::kTestModelName,
900 test_util::kAspiredVersions);
902 ASSERT_EQ(1, two_version_config.model_config_list().config().size());
903 test_util::MutateModelConfig(&two_version_config)
904 .SetLabelVersion(
"A", test_util::kTestModelVersion)
905 .SetLabelVersion(
"B", test_util::kTestModelLargerVersion);
906 TF_ASSERT_OK(server_core->ReloadConfig(two_version_config));
910 ASSERT_EQ(1, two_version_config.model_config_list().config().size());
911 test_util::MutateModelConfig(&two_version_config)
912 .SetLabelVersion(
"A", test_util::kTestModelBogusVersion);
913 TF_ASSERT_OK(server_core->ReloadConfig(two_version_config));
916 TEST_P(ServerCoreTest, VersionLabelsNotAllowed) {
917 ServerCore::Options server_core_options = GetDefaultOptions();
918 server_core_options.allow_version_labels =
false;
919 ModelServerConfig config = GetTestModelServerConfigForFakePlatform();
920 std::unique_ptr<ServerCore> server_core;
922 CreateServerCore(config, std::move(server_core_options), &server_core));
924 test_util::WaitUntilVersionsAvailable(*server_core->servable_state_monitor(),
925 test_util::kTestModelName,
926 {test_util::kTestModelVersion});
928 ASSERT_EQ(1, config.model_config_list().config().size());
929 test_util::MutateModelConfig(&config).SetLabelVersion(
930 "A", test_util::kTestModelVersion);
931 Status status = server_core->ReloadConfig(config);
932 ASSERT_FALSE(status.ok());
935 ::testing::HasSubstr(
"Model version labels are not currently allowed"));
938 TEST_P(ServerCoreTest, StoragePathPrefixOption) {
939 if (PrefixPathsWithURIScheme()) {
942 if (GetTestType() != SAVED_MODEL) {
948 ModelServerConfig config = GetTestModelServerConfigForFakePlatform();
949 string base_path = config.model_config_list().config(0).base_path();
950 const string path_prefix = tensorflow::io::JoinPath(
951 getenv(
"TEST_SRCDIR"),
"tf_serving/external/org_tensorflow/tensorflow/");
952 config.mutable_model_config_list()->mutable_config(0)->set_base_path(
953 string(absl::StripPrefix(base_path, path_prefix)));
954 ServerCore::Options options = GetDefaultOptions();
955 options.storage_path_prefix = path_prefix;
956 std::unique_ptr<ServerCore> server_core;
957 TF_ASSERT_OK(CreateServerCore(GetTestModelServerConfigForFakePlatform(),
958 std::move(options), &server_core));
960 const std::vector<ServableId> available_servables =
961 server_core->ListAvailableServableIds();
962 ASSERT_EQ(available_servables.size(), 1);
963 const ServableId expected_id = {test_util::kTestModelName,
964 test_util::kTestModelVersion};
965 EXPECT_EQ(available_servables.at(0), expected_id);
967 ModelSpec model_spec;
968 model_spec.set_name(test_util::kTestModelName);
969 model_spec.mutable_version()->set_value(test_util::kTestModelVersion);
970 ServableHandle<string> servable_handle;
972 server_core->GetServableHandle<
string>(model_spec, &servable_handle));
973 EXPECT_EQ(servable_handle.id(), expected_id);
976 INSTANTIATE_TEST_CASE_P(
977 TestType, ServerCoreTest,
979 IsTensorflowServingOSS()
981 static_cast<int>(test_util::ServerCoreTest::SAVED_MODEL),
982 static_cast<int>(test_util::ServerCoreTest::NUM_TEST_TYPES))
984 0,
static_cast<int>(ServerCoreTest::NUM_TEST_TYPES)),
987 INSTANTIATE_TEST_CASE_P(
988 TestType, RelativePathsServerCoreTest,
990 IsTensorflowServingOSS()
992 static_cast<int>(test_util::ServerCoreTest::SAVED_MODEL),
993 static_cast<int>(test_util::ServerCoreTest::NUM_TEST_TYPES))
995 0,
static_cast<int>(ServerCoreTest::NUM_TEST_TYPES)),
static Status Create(Options options, std::unique_ptr< ServerCore > *core)