TensorFlow Serving C++ API Documentation
availability_preserving_policy_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/availability_preserving_policy.h"
17 
18 #include <vector>
19 
20 #include <gtest/gtest.h>
21 #include "tensorflow_serving/core/servable_id.h"
22 
23 namespace tensorflow {
24 namespace serving {
25 namespace {
26 
27 // None unloadable (ready+unaspired); multiple loadable (new+aspired). Loads the
28 // highest loadable version.
29 TEST(AvailabilityPreservingPolicyTest, LoadsNewAspired) {
30  std::vector<AspiredServableStateSnapshot> versions;
31  versions.push_back({{"test", 1}, LoaderHarness::State::kUnloading, false});
32  versions.push_back({{"test", 2}, LoaderHarness::State::kError, false});
33  versions.push_back({{"test", 3}, LoaderHarness::State::kReady, true});
34  versions.push_back({{"test", 4}, LoaderHarness::State::kNew, true});
35  versions.push_back({{"test", 5}, LoaderHarness::State::kNew, true});
36 
37  AvailabilityPreservingPolicy policy;
38  auto action = policy.GetNextAction(versions);
39  ASSERT_TRUE(action);
40  EXPECT_EQ(AspiredVersionPolicy::Action::kLoad, action->action);
41  EXPECT_EQ(5, action->id.version);
42 }
43 
44 // Both unloadable and loadable versions present. Unloading doesn't compromise
45 // availability. Opts to unload.
46 TEST(AvailabilityPreservingPolicyTest, UnloadsNonAspiredFirst) {
47  std::vector<AspiredServableStateSnapshot> versions;
48  versions.push_back({{"test", 1}, LoaderHarness::State::kUnloading, false});
49  versions.push_back({{"test", 2}, LoaderHarness::State::kError, false});
50  versions.push_back({{"test", 3}, LoaderHarness::State::kReady, false});
51  versions.push_back({{"test", 4}, LoaderHarness::State::kReady, true});
52  versions.push_back({{"test", 5}, LoaderHarness::State::kNew, true});
53 
54  AvailabilityPreservingPolicy policy;
55  auto action = policy.GetNextAction(versions);
56  ASSERT_TRUE(action);
57  EXPECT_EQ(AspiredVersionPolicy::Action::kUnload, action->action);
58  EXPECT_EQ(3, action->id.version);
59 }
60 
61 // One unloadable. Nothing aspired so the goal is to unload all versions and
62 // lose availability. Unloads.
63 TEST(AvailabilityPreservingPolicyTest, UnloadsFirstNonAspiredWhenNoAspired) {
64  std::vector<AspiredServableStateSnapshot> versions;
65  versions.push_back({{"test", 1}, LoaderHarness::State::kDisabled, false});
66  versions.push_back({{"test", 2}, LoaderHarness::State::kReady, false});
67  versions.push_back({{"test", 3}, LoaderHarness::State::kError, false});
68 
69  AvailabilityPreservingPolicy policy;
70  const auto action = policy.GetNextAction(versions);
71  ASSERT_TRUE(action);
72  EXPECT_EQ(AspiredVersionPolicy::Action::kUnload, action->action);
73  EXPECT_EQ(2, action->id.version);
74 }
75 
76 // None unloadable or loadable. Takes no action.
77 TEST(AvailabilityPreservingPolicyTest, ReturnsNoActionWhenNone) {
78  std::vector<AspiredServableStateSnapshot> versions;
79  versions.push_back({{"test", 1}, LoaderHarness::State::kReady, true});
80  versions.push_back({{"test", 2}, LoaderHarness::State::kError, true});
81  versions.push_back({{"test", 3}, LoaderHarness::State::kLoading, true});
82  versions.push_back({{"test", 4}, LoaderHarness::State::kUnloading, false});
83  versions.push_back({{"test", 5}, LoaderHarness::State::kDisabled, false});
84 
85  AvailabilityPreservingPolicy policy;
86  const auto action = policy.GetNextAction(versions);
87  EXPECT_FALSE(action);
88 }
89 
90 // One unloadable; none loadable. Unloading would compromise availability. Takes
91 // no action.
92 TEST(AvailabilityPreservingPolicyTest, DoesNotUnloadWhenOtherNotReady) {
93  std::vector<AspiredServableStateSnapshot> versions;
94  versions.push_back({{"test", 1}, LoaderHarness::State::kReady, false});
95  versions.push_back({{"test", 2}, LoaderHarness::State::kLoading, true});
96 
97  AvailabilityPreservingPolicy policy;
98  const auto action = policy.GetNextAction(versions);
99  EXPECT_FALSE(action);
100 }
101 
102 // One unloadable; none loadable. Unloading would compromise availability. Takes
103 // no action.
104 TEST(AvailabilityPreservingPolicyTest, DoesNotUnloadWhenOtherInError) {
105  std::vector<AspiredServableStateSnapshot> versions;
106  versions.push_back({{"test", 1}, LoaderHarness::State::kReady, false});
107  versions.push_back({{"test", 2}, LoaderHarness::State::kError, true});
108 
109  AvailabilityPreservingPolicy policy;
110  const auto action = policy.GetNextAction(versions);
111  EXPECT_FALSE(action);
112 }
113 
114 // One unloadable; none loadable. Unloading doesn't compromise availability.
115 // Unloads.
116 TEST(AvailabilityPreservingPolicyTest, UnloadIfOtherReadyEvenIfLoading) {
117  std::vector<AspiredServableStateSnapshot> versions;
118  versions.push_back({{"test", 1}, LoaderHarness::State::kReady, false});
119  versions.push_back({{"test", 2}, LoaderHarness::State::kLoading, true});
120  versions.push_back({{"test", 3}, LoaderHarness::State::kReady, true});
121 
122  AvailabilityPreservingPolicy policy;
123  const auto action = policy.GetNextAction(versions);
124  ASSERT_TRUE(action);
125  EXPECT_EQ(AspiredVersionPolicy::Action::kUnload, action->action);
126  EXPECT_EQ(1, action->id.version);
127 }
128 
129 // One unloadable; none loadable. Unloading doesn't compromise availability.
130 // Unloads.
131 TEST(AvailabilityPreservingPolicyTest, UnloadIfOtherReadyEvenIfError) {
132  std::vector<AspiredServableStateSnapshot> versions;
133  versions.push_back({{"test", 1}, LoaderHarness::State::kReady, false});
134  versions.push_back({{"test", 2}, LoaderHarness::State::kError, true});
135  versions.push_back({{"test", 3}, LoaderHarness::State::kReady, true});
136 
137  AvailabilityPreservingPolicy policy;
138  const auto action = policy.GetNextAction(versions);
139  ASSERT_TRUE(action);
140  EXPECT_EQ(AspiredVersionPolicy::Action::kUnload, action->action);
141  EXPECT_EQ(1, action->id.version);
142 }
143 
144 // Multiple unloadable; none loadable. Availability is achieved despite no
145 // aspired versions being loaded, because one or more non-aspired versions are
146 // loaded. Unloading one non-aspired version doesn't compromise availability.
147 // Unloads the lowest such version.
148 TEST(AvailabilityPreservingPolicyTest, UnloadIfNoAspiredVersionsReady) {
149  std::vector<AspiredServableStateSnapshot> versions;
150  versions.push_back({{"test", 2}, LoaderHarness::State::kReady, false});
151  versions.push_back({{"test", 1}, LoaderHarness::State::kReady, false});
152  versions.push_back({{"test", 3}, LoaderHarness::State::kError, true});
153  versions.push_back({{"test", 4}, LoaderHarness::State::kLoading, true});
154 
155  AvailabilityPreservingPolicy policy;
156  const auto action = policy.GetNextAction(versions);
157  ASSERT_TRUE(action);
158  EXPECT_EQ(AspiredVersionPolicy::Action::kUnload, action->action);
159  EXPECT_EQ(1, action->id.version);
160 }
161 
162 } // namespace
163 } // namespace serving
164 } // namespace tensorflow
@ kReady
'loader_->Load()' has succeeded.
@ kDisabled
'loader_->Unload()' has finished.
@ kLoading
'loader_->Load()' has been called.
@ kUnloading
'loader_->Unload()' has been called.