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