TensorFlow Serving C++ API Documentation
dynamic_source_router_test.cc
1 /* Copyright 2016 Google Inc. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7  http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #include "tensorflow_serving/core/dynamic_source_router.h"
17 
18 #include <algorithm>
19 #include <memory>
20 #include <utility>
21 #include <vector>
22 
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25 #include "tensorflow/core/lib/core/status.h"
26 #include "tensorflow/core/lib/core/status_test_util.h"
27 #include "tensorflow/core/lib/core/stringpiece.h"
28 #include "tensorflow/core/platform/types.h"
29 #include "tensorflow_serving/core/servable_data.h"
30 #include "tensorflow_serving/core/source.h"
31 #include "tensorflow_serving/core/storage_path.h"
32 #include "tensorflow_serving/core/target.h"
33 #include "tensorflow_serving/core/test_util/mock_storage_path_target.h"
34 
35 using ::testing::ElementsAre;
36 using ::testing::Eq;
37 using ::testing::StrictMock;
38 
39 namespace tensorflow {
40 namespace serving {
41 namespace {
42 
43 TEST(DynamicSourceRouterTest, InvalidRouteMap) {
44  std::unique_ptr<DynamicSourceRouter<StoragePath>> router;
45  // Negative output port.
46  EXPECT_FALSE(
47  DynamicSourceRouter<string>::Create(2, {{"foo", -1}}, &router).ok());
48  // Out of range output port.
49  EXPECT_FALSE(
50  DynamicSourceRouter<string>::Create(2, {{"foo", 2}}, &router).ok());
51  // Using reserved (last) output port.
52  EXPECT_FALSE(
53  DynamicSourceRouter<string>::Create(2, {{"foo", 1}}, &router).ok());
54 }
55 
56 TEST(DynamicSourceRouterTest, ReconfigureToInvalidRouteMap) {
57  std::unique_ptr<DynamicSourceRouter<StoragePath>> router;
58  TF_ASSERT_OK(DynamicSourceRouter<string>::Create(2, {{"foo", 0}}, &router));
59  // Negative output port.
60  EXPECT_FALSE(router->UpdateRoutes({{"foo", -1}}).ok());
61  // Out of range output port.
62  EXPECT_FALSE(router->UpdateRoutes({{"foo", 2}}).ok());
63  // Using reserved (last) output port.
64  EXPECT_FALSE(router->UpdateRoutes({{"foo", 1}}).ok());
65 }
66 
67 TEST(DynamicSourceRouterTest, Basic) {
68  std::unique_ptr<DynamicSourceRouter<StoragePath>> router;
69  DynamicSourceRouter<StoragePath>::Routes routes = {{"foo", 0}, {"bar", 1}};
70  TF_ASSERT_OK(DynamicSourceRouter<string>::Create(4, routes, &router));
71  EXPECT_EQ(routes, router->GetRoutes());
72  std::vector<Source<StoragePath>*> output_ports = router->GetOutputPorts();
73  ASSERT_EQ(4, output_ports.size());
74  std::vector<std::unique_ptr<test_util::MockStoragePathTarget>> targets;
75  for (int i = 0; i < output_ports.size(); ++i) {
76  std::unique_ptr<test_util::MockStoragePathTarget> target(
77  new StrictMock<test_util::MockStoragePathTarget>);
78  ConnectSourceToTarget(output_ports[i], target.get());
79  targets.push_back(std::move(target));
80  }
81 
82  // "foo" goes to port 0.
83  EXPECT_CALL(*targets[0], SetAspiredVersions(
84  Eq("foo"), ElementsAre(ServableData<StoragePath>(
85  {"foo", 7}, "data"))));
86  router->SetAspiredVersions("foo",
87  {ServableData<StoragePath>({"foo", 7}, "data")});
88 
89  // "bar" goes to port 1.
90  EXPECT_CALL(*targets[1], SetAspiredVersions(
91  Eq("bar"), ElementsAre(ServableData<StoragePath>(
92  {"bar", 7}, "data"))));
93  router->SetAspiredVersions("bar",
94  {ServableData<StoragePath>({"bar", 7}, "data")});
95 
96  // Servable whose name doesn't match any route goes to the last port (port 3).
97  EXPECT_CALL(*targets[3],
98  SetAspiredVersions(Eq("not_foo_or_bar"),
99  ElementsAre(ServableData<StoragePath>(
100  {"not_foo_or_bar", 7}, "data"))));
101  router->SetAspiredVersions(
102  "not_foo_or_bar",
103  {ServableData<StoragePath>({"not_foo_or_bar", 7}, "data")});
104 }
105 
106 TEST(DynamicSourceRouterTest, Reconfigure) {
107  std::unique_ptr<DynamicSourceRouter<StoragePath>> router;
108  TF_ASSERT_OK(DynamicSourceRouter<string>::Create(2, {{"foo", 0}}, &router));
109  std::vector<Source<StoragePath>*> output_ports = router->GetOutputPorts();
110  ASSERT_EQ(2, output_ports.size());
111  std::vector<std::unique_ptr<test_util::MockStoragePathTarget>> targets;
112  for (int i = 0; i < output_ports.size(); ++i) {
113  std::unique_ptr<test_util::MockStoragePathTarget> target(
114  new StrictMock<test_util::MockStoragePathTarget>);
115  ConnectSourceToTarget(output_ports[i], target.get());
116  targets.push_back(std::move(target));
117  }
118 
119  // Initially, "foo" goes to port 0 and "bar" goes to the default (port 1).
120  EXPECT_CALL(*targets[0], SetAspiredVersions(
121  Eq("foo"), ElementsAre(ServableData<StoragePath>(
122  {"foo", 7}, "data"))));
123  router->SetAspiredVersions("foo",
124  {ServableData<StoragePath>({"foo", 7}, "data")});
125  EXPECT_CALL(*targets[1], SetAspiredVersions(
126  Eq("bar"), ElementsAre(ServableData<StoragePath>(
127  {"bar", 7}, "data"))));
128  router->SetAspiredVersions("bar",
129  {ServableData<StoragePath>({"bar", 7}, "data")});
130 
131  TF_ASSERT_OK(router->UpdateRoutes({{"bar", 0}}));
132 
133  // Now, the routes of "foo" and "bar" should be swapped.
134  EXPECT_CALL(*targets[1], SetAspiredVersions(
135  Eq("foo"), ElementsAre(ServableData<StoragePath>(
136  {"foo", 7}, "data"))));
137  router->SetAspiredVersions("foo",
138  {ServableData<StoragePath>({"foo", 7}, "data")});
139  EXPECT_CALL(*targets[0], SetAspiredVersions(
140  Eq("bar"), ElementsAre(ServableData<StoragePath>(
141  {"bar", 7}, "data"))));
142  router->SetAspiredVersions("bar",
143  {ServableData<StoragePath>({"bar", 7}, "data")});
144 }
145 
146 } // namespace
147 } // namespace serving
148 } // namespace tensorflow