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 "MockPreparedModel.h"
18
19 #include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22 #include <nnapi/IExecution.h>
23 #include <nnapi/IPreparedModel.h>
24 #include <nnapi/TypeUtils.h>
25 #include <nnapi/Types.h>
26 #include <nnapi/hal/1.0/PreparedModel.h>
27
28 #include <functional>
29 #include <memory>
30
31 namespace android::hardware::neuralnetworks::V1_0::utils {
32 namespace {
33
34 using ::testing::_;
35 using ::testing::Invoke;
36 using ::testing::InvokeWithoutArgs;
37
38 const sp<V1_0::IPreparedModel> kInvalidPreparedModel;
39
createMockPreparedModel()40 sp<MockPreparedModel> createMockPreparedModel() {
41 return MockPreparedModel::create();
42 }
43
makeExecute(V1_0::ErrorStatus launchStatus,V1_0::ErrorStatus returnStatus)44 auto makeExecute(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus) {
45 return [launchStatus, returnStatus](
46 const V1_0::Request& /*request*/,
47 const sp<V1_0::IExecutionCallback>& cb) -> Return<V1_0::ErrorStatus> {
48 cb->notify(returnStatus);
49 return launchStatus;
50 };
51 }
52
makeTransportFailure(status_t status)53 std::function<hardware::Status()> makeTransportFailure(status_t status) {
54 return [status] { return hardware::Status::fromStatusT(status); };
55 }
56
57 const auto makeGeneralTransportFailure = makeTransportFailure(NO_MEMORY);
58 const auto makeDeadObjectFailure = makeTransportFailure(DEAD_OBJECT);
59
60 } // namespace
61
TEST(PreparedModelTest,invalidPreparedModel)62 TEST(PreparedModelTest, invalidPreparedModel) {
63 // run test
64 const auto result = PreparedModel::create(kInvalidPreparedModel);
65
66 // verify result
67 ASSERT_FALSE(result.has_value());
68 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
69 }
70
TEST(PreparedModelTest,linkToDeathError)71 TEST(PreparedModelTest, linkToDeathError) {
72 // setup call
73 const auto mockPreparedModel = createMockPreparedModel();
74 const auto ret = []() -> Return<bool> { return false; };
75 EXPECT_CALL(*mockPreparedModel, linkToDeathRet()).Times(1).WillOnce(InvokeWithoutArgs(ret));
76
77 // run test
78 const auto result = PreparedModel::create(mockPreparedModel);
79
80 // verify result
81 ASSERT_FALSE(result.has_value());
82 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
83 }
84
TEST(PreparedModelTest,linkToDeathTransportFailure)85 TEST(PreparedModelTest, linkToDeathTransportFailure) {
86 // setup call
87 const auto mockPreparedModel = createMockPreparedModel();
88 EXPECT_CALL(*mockPreparedModel, linkToDeathRet())
89 .Times(1)
90 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
91
92 // run test
93 const auto result = PreparedModel::create(mockPreparedModel);
94
95 // verify result
96 ASSERT_FALSE(result.has_value());
97 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
98 }
99
TEST(PreparedModelTest,linkToDeathDeadObject)100 TEST(PreparedModelTest, linkToDeathDeadObject) {
101 // setup call
102 const auto mockPreparedModel = createMockPreparedModel();
103 EXPECT_CALL(*mockPreparedModel, linkToDeathRet())
104 .Times(1)
105 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
106
107 // run test
108 const auto result = PreparedModel::create(mockPreparedModel);
109
110 // verify result
111 ASSERT_FALSE(result.has_value());
112 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
113 }
114
TEST(PreparedModelTest,execute)115 TEST(PreparedModelTest, execute) {
116 // setup call
117 const auto mockPreparedModel = createMockPreparedModel();
118 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
119 EXPECT_CALL(*mockPreparedModel, execute(_, _))
120 .Times(1)
121 .WillOnce(Invoke(makeExecute(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE)));
122
123 // run test
124 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
125
126 // verify result
127 EXPECT_TRUE(result.has_value())
128 << "Failed with " << result.error().code << ": " << result.error().message;
129 }
130
TEST(PreparedModelTest,executeLaunchError)131 TEST(PreparedModelTest, executeLaunchError) {
132 // setup test
133 const auto mockPreparedModel = createMockPreparedModel();
134 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
135 EXPECT_CALL(*mockPreparedModel, execute(_, _))
136 .Times(1)
137 .WillOnce(Invoke(makeExecute(V1_0::ErrorStatus::GENERAL_FAILURE,
138 V1_0::ErrorStatus::GENERAL_FAILURE)));
139
140 // run test
141 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
142
143 // verify result
144 ASSERT_FALSE(result.has_value());
145 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
146 }
147
TEST(PreparedModelTest,executeReturnError)148 TEST(PreparedModelTest, executeReturnError) {
149 // setup test
150 const auto mockPreparedModel = createMockPreparedModel();
151 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
152 EXPECT_CALL(*mockPreparedModel, execute(_, _))
153 .Times(1)
154 .WillOnce(Invoke(
155 makeExecute(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE)));
156
157 // run test
158 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
159
160 // verify result
161 ASSERT_FALSE(result.has_value());
162 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
163 }
164
TEST(PreparedModelTest,executeTransportFailure)165 TEST(PreparedModelTest, executeTransportFailure) {
166 // setup test
167 const auto mockPreparedModel = createMockPreparedModel();
168 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
169 EXPECT_CALL(*mockPreparedModel, execute(_, _))
170 .Times(1)
171 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
172
173 // run test
174 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
175
176 // verify result
177 ASSERT_FALSE(result.has_value());
178 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
179 }
180
TEST(PreparedModelTest,executeDeadObject)181 TEST(PreparedModelTest, executeDeadObject) {
182 // setup test
183 const auto mockPreparedModel = createMockPreparedModel();
184 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
185 EXPECT_CALL(*mockPreparedModel, execute(_, _))
186 .Times(1)
187 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
188
189 // run test
190 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
191
192 // verify result
193 ASSERT_FALSE(result.has_value());
194 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
195 }
196
TEST(PreparedModelTest,executeCrash)197 TEST(PreparedModelTest, executeCrash) {
198 // setup test
199 const auto mockPreparedModel = createMockPreparedModel();
200 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
201 const auto ret = [&mockPreparedModel]() -> hardware::Return<V1_0::ErrorStatus> {
202 mockPreparedModel->simulateCrash();
203 return V1_0::ErrorStatus::NONE;
204 };
205 EXPECT_CALL(*mockPreparedModel, execute(_, _)).Times(1).WillOnce(InvokeWithoutArgs(ret));
206
207 // run test
208 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
209
210 // verify result
211 ASSERT_FALSE(result.has_value());
212 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
213 }
214
TEST(PreparedModelTest,executeFencedNotSupported)215 TEST(PreparedModelTest, executeFencedNotSupported) {
216 // setup test
217 const auto mockPreparedModel = createMockPreparedModel();
218 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
219
220 // run test
221 const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
222
223 // verify result
224 ASSERT_FALSE(result.has_value());
225 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
226 }
227
TEST(PreparedModelTest,reusableExecute)228 TEST(PreparedModelTest, reusableExecute) {
229 // setup call
230 const uint32_t kNumberOfComputations = 2;
231 const auto mockPreparedModel = createMockPreparedModel();
232 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
233 EXPECT_CALL(*mockPreparedModel, execute(_, _))
234 .Times(kNumberOfComputations)
235 .WillRepeatedly(Invoke(makeExecute(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE)));
236
237 // create execution
238 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
239 ASSERT_TRUE(createResult.has_value())
240 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
241 ASSERT_NE(createResult.value(), nullptr);
242
243 // invoke compute repeatedly
244 for (uint32_t i = 0; i < kNumberOfComputations; i++) {
245 const auto computeResult = createResult.value()->compute({});
246 EXPECT_TRUE(computeResult.has_value()) << "Failed with " << computeResult.error().code
247 << ": " << computeResult.error().message;
248 }
249 }
250
TEST(PreparedModelTest,reusableExecuteLaunchError)251 TEST(PreparedModelTest, reusableExecuteLaunchError) {
252 // setup test
253 const auto mockPreparedModel = createMockPreparedModel();
254 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
255 EXPECT_CALL(*mockPreparedModel, execute(_, _))
256 .Times(1)
257 .WillOnce(Invoke(makeExecute(V1_0::ErrorStatus::GENERAL_FAILURE,
258 V1_0::ErrorStatus::GENERAL_FAILURE)));
259
260 // create execution
261 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
262 ASSERT_TRUE(createResult.has_value())
263 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
264 ASSERT_NE(createResult.value(), nullptr);
265
266 // invoke compute
267 const auto computeResult = createResult.value()->compute({});
268 ASSERT_FALSE(computeResult.has_value());
269 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
270 }
271
TEST(PreparedModelTest,reusableExecuteReturnError)272 TEST(PreparedModelTest, reusableExecuteReturnError) {
273 // setup test
274 const auto mockPreparedModel = createMockPreparedModel();
275 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
276 EXPECT_CALL(*mockPreparedModel, execute(_, _))
277 .Times(1)
278 .WillOnce(Invoke(
279 makeExecute(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE)));
280
281 // create execution
282 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
283 ASSERT_TRUE(createResult.has_value())
284 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
285 ASSERT_NE(createResult.value(), nullptr);
286
287 // invoke compute
288 const auto computeResult = createResult.value()->compute({});
289 ASSERT_FALSE(computeResult.has_value());
290 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
291 }
292
TEST(PreparedModelTest,reusableExecuteTransportFailure)293 TEST(PreparedModelTest, reusableExecuteTransportFailure) {
294 // setup test
295 const auto mockPreparedModel = createMockPreparedModel();
296 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
297 EXPECT_CALL(*mockPreparedModel, execute(_, _))
298 .Times(1)
299 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
300
301 // create execution
302 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
303 ASSERT_TRUE(createResult.has_value())
304 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
305 ASSERT_NE(createResult.value(), nullptr);
306
307 // invoke compute
308 const auto computeResult = createResult.value()->compute({});
309 ASSERT_FALSE(computeResult.has_value());
310 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
311 }
312
TEST(PreparedModelTest,reusableExecuteDeadObject)313 TEST(PreparedModelTest, reusableExecuteDeadObject) {
314 // setup test
315 const auto mockPreparedModel = createMockPreparedModel();
316 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
317 EXPECT_CALL(*mockPreparedModel, execute(_, _))
318 .Times(1)
319 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
320
321 // create execution
322 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
323 ASSERT_TRUE(createResult.has_value())
324 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
325 ASSERT_NE(createResult.value(), nullptr);
326
327 // invoke compute
328 const auto computeResult = createResult.value()->compute({});
329 ASSERT_FALSE(computeResult.has_value());
330 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::DEAD_OBJECT);
331 }
332
TEST(PreparedModelTest,reusableExecuteCrash)333 TEST(PreparedModelTest, reusableExecuteCrash) {
334 // setup test
335 const auto mockPreparedModel = createMockPreparedModel();
336 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
337 const auto ret = [&mockPreparedModel]() -> hardware::Return<V1_0::ErrorStatus> {
338 mockPreparedModel->simulateCrash();
339 return V1_0::ErrorStatus::NONE;
340 };
341 EXPECT_CALL(*mockPreparedModel, execute(_, _)).Times(1).WillOnce(InvokeWithoutArgs(ret));
342
343 // create execution
344 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
345 ASSERT_TRUE(createResult.has_value())
346 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
347 ASSERT_NE(createResult.value(), nullptr);
348
349 // invoke compute
350 const auto computeResult = createResult.value()->compute({});
351 ASSERT_FALSE(computeResult.has_value());
352 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::DEAD_OBJECT);
353 }
354
TEST(PreparedModelTest,reusableExecuteFencedNotSupported)355 TEST(PreparedModelTest, reusableExecuteFencedNotSupported) {
356 // setup test
357 const auto mockPreparedModel = createMockPreparedModel();
358 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
359
360 // create execution
361 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
362 ASSERT_TRUE(createResult.has_value())
363 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
364 ASSERT_NE(createResult.value(), nullptr);
365
366 // invoke compute
367 const auto computeResult = createResult.value()->computeFenced({}, {}, {});
368 ASSERT_FALSE(computeResult.has_value());
369 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
370 }
371
TEST(PreparedModelTest,configureExecutionBurst)372 TEST(PreparedModelTest, configureExecutionBurst) {
373 // setup test
374 const auto mockPreparedModel = MockPreparedModel::create();
375 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
376
377 // run test
378 const auto result = preparedModel->configureExecutionBurst();
379
380 // verify result
381 ASSERT_TRUE(result.has_value())
382 << "Failed with " << result.error().code << ": " << result.error().message;
383 EXPECT_NE(result.value(), nullptr);
384 }
385
TEST(PreparedModelTest,getUnderlyingResource)386 TEST(PreparedModelTest, getUnderlyingResource) {
387 // setup test
388 const auto mockPreparedModel = createMockPreparedModel();
389 const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
390
391 // run test
392 const auto resource = preparedModel->getUnderlyingResource();
393
394 // verify resource
395 const sp<V1_0::IPreparedModel>* maybeMock = std::any_cast<sp<V1_0::IPreparedModel>>(&resource);
396 ASSERT_NE(maybeMock, nullptr);
397 EXPECT_EQ(maybeMock->get(), mockPreparedModel.get());
398 }
399
400 } // namespace android::hardware::neuralnetworks::V1_0::utils
401