• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gmock/gmock.h>
18 #include <nnapi/TypeUtils.h>
19 #include <nnapi/Types.h>
20 #include <nnapi/hal/ResilientPreparedModel.h>
21 #include <utility>
22 #include "MockPreparedModel.h"
23 
24 namespace android::hardware::neuralnetworks::utils {
25 namespace {
26 
27 using ::testing::_;
28 using ::testing::InvokeWithoutArgs;
29 using ::testing::Return;
30 
31 using SharedMockPreparedModel = std::shared_ptr<const nn::MockPreparedModel>;
32 using MockPreparedModelFactory =
33         ::testing::MockFunction<nn::GeneralResult<nn::SharedPreparedModel>()>;
34 
createConfiguredMockPreparedModel()35 SharedMockPreparedModel createConfiguredMockPreparedModel() {
36     return std::make_shared<const nn::MockPreparedModel>();
37 }
38 
39 std::tuple<std::shared_ptr<const nn::MockPreparedModel>, std::unique_ptr<MockPreparedModelFactory>,
40            std::shared_ptr<const ResilientPreparedModel>>
setup()41 setup() {
42     auto mockPreparedModel = std::make_shared<const nn::MockPreparedModel>();
43 
44     auto mockPreparedModelFactory = std::make_unique<MockPreparedModelFactory>();
45     EXPECT_CALL(*mockPreparedModelFactory, Call()).Times(1).WillOnce(Return(mockPreparedModel));
46 
47     auto buffer = ResilientPreparedModel::create(mockPreparedModelFactory->AsStdFunction()).value();
48     return std::make_tuple(std::move(mockPreparedModel), std::move(mockPreparedModelFactory),
49                            std::move(buffer));
50 }
51 
__anon00b0e2e10202(nn::ErrorStatus status) 52 constexpr auto makeError = [](nn::ErrorStatus status) {
53     return [status](const auto&... /*args*/) { return nn::error(status); };
54 };
55 const auto kReturnGeneralFailure = makeError(nn::ErrorStatus::GENERAL_FAILURE);
56 const auto kReturnDeadObject = makeError(nn::ErrorStatus::DEAD_OBJECT);
57 
58 const auto kNoCreateReusableExecutionError = nn::GeneralResult<nn::SharedExecution>{};
59 const auto kNoExecutionError =
60         nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>{};
61 const auto kNoFencedExecutionError =
62         nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>(
63                 std::make_pair(nn::SyncFence::createAsSignaled(), nullptr));
64 
65 struct FakeResource {};
66 
67 }  // namespace
68 
TEST(ResilientPreparedModelTest,invalidPreparedModelFactory)69 TEST(ResilientPreparedModelTest, invalidPreparedModelFactory) {
70     // setup call
71     const auto invalidPreparedModelFactory = ResilientPreparedModel::Factory{};
72 
73     // run test
74     const auto result = ResilientPreparedModel::create(invalidPreparedModelFactory);
75 
76     // verify result
77     ASSERT_FALSE(result.has_value());
78     EXPECT_EQ(result.error().code, nn::ErrorStatus::INVALID_ARGUMENT);
79 }
80 
TEST(ResilientPreparedModelTest,preparedModelFactoryFailure)81 TEST(ResilientPreparedModelTest, preparedModelFactoryFailure) {
82     // setup call
83     const auto invalidPreparedModelFactory = kReturnGeneralFailure;
84 
85     // run test
86     const auto result = ResilientPreparedModel::create(invalidPreparedModelFactory);
87 
88     // verify result
89     ASSERT_FALSE(result.has_value());
90     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
91 }
92 
TEST(ResilientPreparedModelTest,getPreparedModel)93 TEST(ResilientPreparedModelTest, getPreparedModel) {
94     // setup call
95     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
96 
97     // run test
98     const auto result = preparedModel->getPreparedModel();
99 
100     // verify result
101     EXPECT_TRUE(result == mockPreparedModel);
102 }
103 
TEST(ResilientPreparedModelTest,execute)104 TEST(ResilientPreparedModelTest, execute) {
105     // setup call
106     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
107     EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _, _, _))
108             .Times(1)
109             .WillOnce(Return(kNoExecutionError));
110 
111     // run test
112     const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
113 
114     // verify result
115     ASSERT_TRUE(result.has_value())
116             << "Failed with " << result.error().code << ": " << result.error().message;
117 }
118 
TEST(ResilientPreparedModelTest,executeError)119 TEST(ResilientPreparedModelTest, executeError) {
120     // setup call
121     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
122     EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _, _, _))
123             .Times(1)
124             .WillOnce(kReturnGeneralFailure);
125 
126     // run test
127     const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
128 
129     // verify result
130     ASSERT_FALSE(result.has_value());
131     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
132 }
133 
TEST(ResilientPreparedModelTest,executeDeadObjectFailedRecovery)134 TEST(ResilientPreparedModelTest, executeDeadObjectFailedRecovery) {
135     // setup call
136     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
137     EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _, _, _)).Times(1).WillOnce(kReturnDeadObject);
138     constexpr auto ret = [] { return nn::error(nn::ErrorStatus::GENERAL_FAILURE); };
139     EXPECT_CALL(*mockPreparedModelFactory, Call()).Times(1).WillOnce(ret);
140 
141     // run test
142     const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
143 
144     // verify result
145     ASSERT_FALSE(result.has_value());
146     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
147 }
148 
TEST(ResilientPreparedModelTest,executeDeadObjectSuccessfulRecovery)149 TEST(ResilientPreparedModelTest, executeDeadObjectSuccessfulRecovery) {
150     // setup call
151     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
152     EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _, _, _)).Times(1).WillOnce(kReturnDeadObject);
153     const auto recoveredMockPreparedModel = createConfiguredMockPreparedModel();
154     EXPECT_CALL(*recoveredMockPreparedModel, execute(_, _, _, _, _, _))
155             .Times(1)
156             .WillOnce(Return(kNoExecutionError));
157     EXPECT_CALL(*mockPreparedModelFactory, Call())
158             .Times(1)
159             .WillOnce(Return(recoveredMockPreparedModel));
160 
161     // run test
162     const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
163 
164     // verify result
165     ASSERT_TRUE(result.has_value())
166             << "Failed with " << result.error().code << ": " << result.error().message;
167 }
168 
TEST(ResilientPreparedModelTest,executeFenced)169 TEST(ResilientPreparedModelTest, executeFenced) {
170     // setup call
171     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
172     EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
173             .Times(1)
174             .WillOnce(Return(kNoFencedExecutionError));
175 
176     // run test
177     const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
178 
179     // verify result
180     ASSERT_TRUE(result.has_value())
181             << "Failed with " << result.error().code << ": " << result.error().message;
182 }
183 
TEST(ResilientPreparedModelTest,executeFencedError)184 TEST(ResilientPreparedModelTest, executeFencedError) {
185     // setup call
186     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
187     EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
188             .Times(1)
189             .WillOnce(kReturnGeneralFailure);
190 
191     // run test
192     const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
193 
194     // verify result
195     ASSERT_FALSE(result.has_value());
196     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
197 }
198 
TEST(ResilientPreparedModelTest,executeFencedDeadObjectFailedRecovery)199 TEST(ResilientPreparedModelTest, executeFencedDeadObjectFailedRecovery) {
200     // setup call
201     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
202     EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
203             .Times(1)
204             .WillOnce(kReturnDeadObject);
205     EXPECT_CALL(*mockPreparedModelFactory, Call()).Times(1).WillOnce(kReturnGeneralFailure);
206 
207     // run test
208     const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
209 
210     // verify result
211     ASSERT_FALSE(result.has_value());
212     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
213 }
214 
TEST(ResilientPreparedModelTest,executeFencedDeadObjectSuccessfulRecovery)215 TEST(ResilientPreparedModelTest, executeFencedDeadObjectSuccessfulRecovery) {
216     // setup call
217     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
218     EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
219             .Times(1)
220             .WillOnce(kReturnDeadObject);
221     const auto recoveredMockPreparedModel = createConfiguredMockPreparedModel();
222     EXPECT_CALL(*recoveredMockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
223             .Times(1)
224             .WillOnce(Return(kNoFencedExecutionError));
225     EXPECT_CALL(*mockPreparedModelFactory, Call())
226             .Times(1)
227             .WillOnce(Return(recoveredMockPreparedModel));
228 
229     // run test
230     const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
231 
232     // verify result
233     ASSERT_TRUE(result.has_value())
234             << "Failed with " << result.error().code << ": " << result.error().message;
235 }
236 
TEST(ResilientPreparedModelTest,createReusableExecution)237 TEST(ResilientPreparedModelTest, createReusableExecution) {
238     // setup call
239     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
240     EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _, _, _))
241             .Times(1)
242             .WillOnce(Return(kNoCreateReusableExecutionError));
243 
244     // run test
245     const auto result = preparedModel->createReusableExecution({}, {}, {}, {}, {});
246 
247     // verify result
248     ASSERT_TRUE(result.has_value())
249             << "Failed with " << result.error().code << ": " << result.error().message;
250 }
251 
TEST(ResilientPreparedModelTest,createReusableExecutionError)252 TEST(ResilientPreparedModelTest, createReusableExecutionError) {
253     // setup call
254     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
255     EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _, _, _))
256             .Times(1)
257             .WillOnce(kReturnGeneralFailure);
258 
259     // run test
260     const auto result = preparedModel->createReusableExecution({}, {}, {}, {}, {});
261 
262     // verify result
263     ASSERT_FALSE(result.has_value());
264     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
265 }
266 
TEST(ResilientPreparedModelTest,getUnderlyingResource)267 TEST(ResilientPreparedModelTest, getUnderlyingResource) {
268     // setup call
269     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
270     EXPECT_CALL(*mockPreparedModel, getUnderlyingResource())
271             .Times(1)
272             .WillOnce(Return(FakeResource{}));
273 
274     // run test
275     const auto resource = preparedModel->getUnderlyingResource();
276 
277     // verify resource
278     const FakeResource* maybeFakeResource = std::any_cast<FakeResource>(&resource);
279     EXPECT_NE(maybeFakeResource, nullptr);
280 }
281 
TEST(ResilientPreparedModelTest,recover)282 TEST(ResilientPreparedModelTest, recover) {
283     // setup call
284     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
285     const auto recoveredMockPreparedModel = createConfiguredMockPreparedModel();
286     EXPECT_CALL(*mockPreparedModelFactory, Call())
287             .Times(1)
288             .WillOnce(Return(recoveredMockPreparedModel));
289 
290     // run test
291     const auto result = preparedModel->recover(mockPreparedModel.get());
292 
293     // verify result
294     ASSERT_TRUE(result.has_value())
295             << "Failed with " << result.error().code << ": " << result.error().message;
296     EXPECT_TRUE(result.value() == recoveredMockPreparedModel);
297 }
298 
TEST(ResilientPreparedModelTest,recoverFailure)299 TEST(ResilientPreparedModelTest, recoverFailure) {
300     // setup call
301     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
302     const auto recoveredMockPreparedModel = createConfiguredMockPreparedModel();
303     EXPECT_CALL(*mockPreparedModelFactory, Call()).Times(1).WillOnce(kReturnGeneralFailure);
304 
305     // run test
306     const auto result = preparedModel->recover(mockPreparedModel.get());
307 
308     // verify result
309     EXPECT_FALSE(result.has_value());
310 }
311 
TEST(ResilientPreparedModelTest,someoneElseRecovered)312 TEST(ResilientPreparedModelTest, someoneElseRecovered) {
313     // setup call
314     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
315     const auto recoveredMockPreparedModel = createConfiguredMockPreparedModel();
316     EXPECT_CALL(*mockPreparedModelFactory, Call())
317             .Times(1)
318             .WillOnce(Return(recoveredMockPreparedModel));
319     preparedModel->recover(mockPreparedModel.get());
320 
321     // run test
322     const auto result = preparedModel->recover(mockPreparedModel.get());
323 
324     // verify result
325     ASSERT_TRUE(result.has_value())
326             << "Failed with " << result.error().code << ": " << result.error().message;
327     EXPECT_TRUE(result.value() == recoveredMockPreparedModel);
328 }
329 
330 }  // namespace android::hardware::neuralnetworks::utils
331