Loading compatibility_matrices/compatibility_matrix.current.xml +1 −0 Original line number Diff line number Diff line Loading @@ -559,6 +559,7 @@ </hal> <hal format="aidl" optional="true"> <name>android.hardware.vibrator</name> <version>1-2</version> <interface> <name>IVibratorManager</name> <instance>default</instance> Loading neuralnetworks/1.0/utils/Android.bp +26 −0 Original line number Diff line number Diff line Loading @@ -32,3 +32,29 @@ cc_library_static { "neuralnetworks_utils_hal_common", ], } cc_test { name: "neuralnetworks_utils_hal_1_0_test", srcs: ["test/*.cpp"], static_libs: [ "android.hardware.neuralnetworks@1.0", "libgmock", "libneuralnetworks_common", "neuralnetworks_types", "neuralnetworks_utils_hal_common", "neuralnetworks_utils_hal_1_0", ], shared_libs: [ "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "libbase", "libcutils", "libfmq", "libhidlbase", "libhidlmemory", "liblog", "libnativewindow", "libutils", ], test_suites: ["general-tests"], } neuralnetworks/1.0/utils/test/DeviceTest.cpp 0 → 100644 +524 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "MockDevice.h" #include "MockPreparedModel.h" #include <android/hardware/neuralnetworks/1.0/IDevice.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <nnapi/IDevice.h> #include <nnapi/TypeUtils.h> #include <nnapi/Types.h> #include <nnapi/hal/1.0/Device.h> #include <functional> #include <memory> #include <string> namespace android::hardware::neuralnetworks::V1_0::utils { namespace { using ::testing::_; using ::testing::Invoke; using ::testing::InvokeWithoutArgs; const nn::Model kSimpleModel = { .main = {.operands = {{.type = nn::OperandType::TENSOR_FLOAT32, .dimensions = {1}, .lifetime = nn::Operand::LifeTime::SUBGRAPH_INPUT}, {.type = nn::OperandType::TENSOR_FLOAT32, .dimensions = {1}, .lifetime = nn::Operand::LifeTime::SUBGRAPH_OUTPUT}}, .operations = {{.type = nn::OperationType::RELU, .inputs = {0}, .outputs = {1}}}, .inputIndexes = {0}, .outputIndexes = {1}}}; const std::string kName = "Google-MockV1"; const std::string kInvalidName = ""; const sp<V1_0::IDevice> kInvalidDevice; constexpr V1_0::PerformanceInfo kNoPerformanceInfo = { .execTime = std::numeric_limits<float>::max(), .powerUsage = std::numeric_limits<float>::max()}; template <typename... Args> auto makeCallbackReturn(Args&&... args) { return [argPack = std::make_tuple(std::forward<Args>(args)...)](const auto& cb) { std::apply(cb, argPack); return Void(); }; } sp<MockDevice> createMockDevice() { const auto mockDevice = MockDevice::create(); // Setup default actions for each relevant call. const auto getCapabilities_ret = makeCallbackReturn( V1_0::ErrorStatus::NONE, V1_0::Capabilities{ .float32Performance = kNoPerformanceInfo, .quantized8Performance = kNoPerformanceInfo, }); // Setup default actions for each relevant call. ON_CALL(*mockDevice, getCapabilities(_)).WillByDefault(Invoke(getCapabilities_ret)); // These EXPECT_CALL(...).Times(testing::AnyNumber()) calls are to suppress warnings on the // uninteresting methods calls. EXPECT_CALL(*mockDevice, getCapabilities(_)).Times(testing::AnyNumber()); return mockDevice; } auto makePreparedModelReturn(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus, const sp<V1_0::utils::MockPreparedModel>& preparedModel) { return [launchStatus, returnStatus, preparedModel](const V1_0::Model& /*model*/, const sp<V1_0::IPreparedModelCallback>& cb) -> hardware::Return<V1_0::ErrorStatus> { cb->notify(returnStatus, preparedModel).isOk(); return launchStatus; }; } std::function<hardware::Status()> makeTransportFailure(status_t status) { return [status] { return hardware::Status::fromStatusT(status); }; } const auto makeGeneralTransportFailure = makeTransportFailure(NO_MEMORY); const auto makeDeadObjectFailure = makeTransportFailure(DEAD_OBJECT); } // namespace TEST(DeviceTest, invalidName) { // run test const auto device = MockDevice::create(); const auto result = Device::create(kInvalidName, device); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::INVALID_ARGUMENT); } TEST(DeviceTest, invalidDevice) { // run test const auto result = Device::create(kName, kInvalidDevice); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::INVALID_ARGUMENT); } TEST(DeviceTest, getCapabilitiesError) { // setup call const auto mockDevice = createMockDevice(); const auto ret = makeCallbackReturn(V1_0::ErrorStatus::GENERAL_FAILURE, V1_0::Capabilities{ .float32Performance = kNoPerformanceInfo, .quantized8Performance = kNoPerformanceInfo, }); EXPECT_CALL(*mockDevice, getCapabilities(_)).Times(1).WillOnce(Invoke(ret)); // run test const auto result = Device::create(kName, mockDevice); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, getCapabilitiesTransportFailure) { // setup call const auto mockDevice = createMockDevice(); EXPECT_CALL(*mockDevice, getCapabilities(_)) .Times(1) .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test const auto result = Device::create(kName, mockDevice); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, getCapabilitiesDeadObject) { // setup call const auto mockDevice = createMockDevice(); EXPECT_CALL(*mockDevice, getCapabilities(_)) .Times(1) .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); // run test const auto result = Device::create(kName, mockDevice); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT); } TEST(DeviceTest, linkToDeathError) { // setup call const auto mockDevice = createMockDevice(); const auto ret = []() -> Return<bool> { return false; }; EXPECT_CALL(*mockDevice, linkToDeathRet()).Times(1).WillOnce(InvokeWithoutArgs(ret)); // run test const auto result = Device::create(kName, mockDevice); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, linkToDeathTransportFailure) { // setup call const auto mockDevice = createMockDevice(); EXPECT_CALL(*mockDevice, linkToDeathRet()) .Times(1) .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test const auto result = Device::create(kName, mockDevice); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, linkToDeathDeadObject) { // setup call const auto mockDevice = createMockDevice(); EXPECT_CALL(*mockDevice, linkToDeathRet()) .Times(1) .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); // run test const auto result = Device::create(kName, mockDevice); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT); } TEST(DeviceTest, getName) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); // run test const auto& name = device->getName(); // verify result EXPECT_EQ(name, kName); } TEST(DeviceTest, getFeatureLevel) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); // run test const auto featureLevel = device->getFeatureLevel(); // verify result EXPECT_EQ(featureLevel, nn::Version::ANDROID_OC_MR1); } TEST(DeviceTest, getCachedData) { // setup call const auto mockDevice = createMockDevice(); const auto result = Device::create(kName, mockDevice); ASSERT_TRUE(result.has_value()) << "Failed with " << result.error().code << ": " << result.error().message; const auto& device = result.value(); // run test and verify results EXPECT_EQ(device->getVersionString(), device->getVersionString()); EXPECT_EQ(device->getType(), device->getType()); EXPECT_EQ(device->getSupportedExtensions(), device->getSupportedExtensions()); EXPECT_EQ(device->getNumberOfCacheFilesNeeded(), device->getNumberOfCacheFilesNeeded()); EXPECT_EQ(device->getCapabilities(), device->getCapabilities()); } TEST(DeviceTest, wait) { // setup call const auto mockDevice = createMockDevice(); const auto ret = []() -> Return<void> { return {}; }; EXPECT_CALL(*mockDevice, ping()).Times(1).WillOnce(InvokeWithoutArgs(ret)); const auto device = Device::create(kName, mockDevice).value(); // run test const auto result = device->wait(); // verify result ASSERT_TRUE(result.has_value()) << "Failed with " << result.error().code << ": " << result.error().message; } TEST(DeviceTest, waitTransportFailure) { // setup call const auto mockDevice = createMockDevice(); EXPECT_CALL(*mockDevice, ping()) .Times(1) .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); const auto device = Device::create(kName, mockDevice).value(); // run test const auto result = device->wait(); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, waitDeadObject) { // setup call const auto mockDevice = createMockDevice(); EXPECT_CALL(*mockDevice, ping()).Times(1).WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); const auto device = Device::create(kName, mockDevice).value(); // run test const auto result = device->wait(); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT); } TEST(DeviceTest, getSupportedOperations) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); const auto ret = [](const auto& model, const auto& cb) { cb(V1_0::ErrorStatus::NONE, std::vector<bool>(model.operations.size(), true)); return hardware::Void(); }; EXPECT_CALL(*mockDevice, getSupportedOperations(_, _)).Times(1).WillOnce(Invoke(ret)); // run test const auto result = device->getSupportedOperations(kSimpleModel); // verify result ASSERT_TRUE(result.has_value()) << "Failed with " << result.error().code << ": " << result.error().message; const auto& supportedOperations = result.value(); EXPECT_EQ(supportedOperations.size(), kSimpleModel.main.operations.size()); EXPECT_THAT(supportedOperations, Each(testing::IsTrue())); } TEST(DeviceTest, getSupportedOperationsError) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); const auto ret = [](const auto& /*model*/, const auto& cb) { cb(V1_0::ErrorStatus::GENERAL_FAILURE, {}); return hardware::Void(); }; EXPECT_CALL(*mockDevice, getSupportedOperations(_, _)).Times(1).WillOnce(Invoke(ret)); // run test const auto result = device->getSupportedOperations(kSimpleModel); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, getSupportedOperationsTransportFailure) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); EXPECT_CALL(*mockDevice, getSupportedOperations(_, _)) .Times(1) .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test const auto result = device->getSupportedOperations(kSimpleModel); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, getSupportedOperationsDeadObject) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); EXPECT_CALL(*mockDevice, getSupportedOperations(_, _)) .Times(1) .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); // run test const auto result = device->getSupportedOperations(kSimpleModel); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT); } TEST(DeviceTest, prepareModel) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); const auto mockPreparedModel = V1_0::utils::MockPreparedModel::create(); EXPECT_CALL(*mockDevice, prepareModel(_, _)) .Times(1) .WillOnce(Invoke(makePreparedModelReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, mockPreparedModel))); // run test const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT, nn::Priority::DEFAULT, {}, {}, {}, {}); // verify result ASSERT_TRUE(result.has_value()) << "Failed with " << result.error().code << ": " << result.error().message; EXPECT_NE(result.value(), nullptr); } TEST(DeviceTest, prepareModelLaunchError) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); EXPECT_CALL(*mockDevice, prepareModel(_, _)) .Times(1) .WillOnce(Invoke(makePreparedModelReturn(V1_0::ErrorStatus::GENERAL_FAILURE, V1_0::ErrorStatus::GENERAL_FAILURE, nullptr))); // run test const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT, nn::Priority::DEFAULT, {}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, prepareModelReturnError) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); EXPECT_CALL(*mockDevice, prepareModel(_, _)) .Times(1) .WillOnce(Invoke(makePreparedModelReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE, nullptr))); // run test const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT, nn::Priority::DEFAULT, {}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, prepareModelNullptrError) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); EXPECT_CALL(*mockDevice, prepareModel(_, _)) .Times(1) .WillOnce(Invoke(makePreparedModelReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, nullptr))); // run test const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT, nn::Priority::DEFAULT, {}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, prepareModelTransportFailure) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); EXPECT_CALL(*mockDevice, prepareModel(_, _)) .Times(1) .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT, nn::Priority::DEFAULT, {}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, prepareModelDeadObject) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); EXPECT_CALL(*mockDevice, prepareModel(_, _)) .Times(1) .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); // run test const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT, nn::Priority::DEFAULT, {}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT); } TEST(DeviceTest, prepareModelAsyncCrash) { // setup test const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); const auto ret = [&mockDevice]() -> hardware::Return<V1_0::ErrorStatus> { mockDevice->simulateCrash(); return V1_0::ErrorStatus::NONE; }; EXPECT_CALL(*mockDevice, prepareModel(_, _)).Times(1).WillOnce(InvokeWithoutArgs(ret)); // run test const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT, nn::Priority::DEFAULT, {}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT); } TEST(DeviceTest, prepareModelFromCacheNotSupported) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); // run test const auto result = device->prepareModelFromCache({}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, allocateNotSupported) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); // run test const auto result = device->allocate({}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } } // namespace android::hardware::neuralnetworks::V1_0::utils neuralnetworks/1.0/utils/test/MockDevice.h 0 → 100644 +86 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_DEVICE #define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_DEVICE #include <android/hardware/neuralnetworks/1.0/IDevice.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <hidl/Status.h> namespace android::hardware::neuralnetworks::V1_0::utils { class MockDevice final : public IDevice { public: static sp<MockDevice> create(); // IBase methods below. MOCK_METHOD(Return<void>, ping, (), (override)); MOCK_METHOD(Return<bool>, linkToDeathRet, ()); Return<bool> linkToDeath(const sp<hidl_death_recipient>& recipient, uint64_t /*cookie*/); // V1_0 methods below. MOCK_METHOD(Return<void>, getCapabilities, (getCapabilities_cb cb), (override)); MOCK_METHOD(Return<void>, getSupportedOperations, (const V1_0::Model& model, getSupportedOperations_cb cb), (override)); MOCK_METHOD(Return<V1_0::ErrorStatus>, prepareModel, (const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& callback), (override)); MOCK_METHOD(Return<V1_0::DeviceStatus>, getStatus, (), (override)); // Helper methods. void simulateCrash(); private: sp<hidl_death_recipient> mDeathRecipient; }; inline sp<MockDevice> MockDevice::create() { auto mockDevice = sp<MockDevice>::make(); // Setup default actions for each relevant call. const auto ret = []() -> Return<bool> { return true; }; // Setup default actions for each relevant call. ON_CALL(*mockDevice, linkToDeathRet()).WillByDefault(testing::Invoke(ret)); // These EXPECT_CALL(...).Times(testing::AnyNumber()) calls are to suppress warnings on the // uninteresting methods calls. EXPECT_CALL(*mockDevice, linkToDeathRet()).Times(testing::AnyNumber()); return mockDevice; } inline Return<bool> MockDevice::linkToDeath(const sp<hidl_death_recipient>& recipient, uint64_t /*cookie*/) { mDeathRecipient = recipient; return linkToDeathRet(); } inline void MockDevice::simulateCrash() { ASSERT_NE(nullptr, mDeathRecipient.get()); // Currently, the utils::Device will not use the `cookie` or `who` arguments, so we pass in 0 // and nullptr for these arguments instead. Normally, they are used by the hidl_death_recipient // to determine which object is dead. However, the utils::Device code only pairs a single death // recipient with a single HIDL interface object, so these arguments are redundant. mDeathRecipient->serviceDied(0, nullptr); } } // namespace android::hardware::neuralnetworks::V1_0::utils #endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_DEVICE Loading
compatibility_matrices/compatibility_matrix.current.xml +1 −0 Original line number Diff line number Diff line Loading @@ -559,6 +559,7 @@ </hal> <hal format="aidl" optional="true"> <name>android.hardware.vibrator</name> <version>1-2</version> <interface> <name>IVibratorManager</name> <instance>default</instance> Loading
neuralnetworks/1.0/utils/Android.bp +26 −0 Original line number Diff line number Diff line Loading @@ -32,3 +32,29 @@ cc_library_static { "neuralnetworks_utils_hal_common", ], } cc_test { name: "neuralnetworks_utils_hal_1_0_test", srcs: ["test/*.cpp"], static_libs: [ "android.hardware.neuralnetworks@1.0", "libgmock", "libneuralnetworks_common", "neuralnetworks_types", "neuralnetworks_utils_hal_common", "neuralnetworks_utils_hal_1_0", ], shared_libs: [ "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "libbase", "libcutils", "libfmq", "libhidlbase", "libhidlmemory", "liblog", "libnativewindow", "libutils", ], test_suites: ["general-tests"], }
neuralnetworks/1.0/utils/test/DeviceTest.cpp 0 → 100644 +524 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "MockDevice.h" #include "MockPreparedModel.h" #include <android/hardware/neuralnetworks/1.0/IDevice.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <nnapi/IDevice.h> #include <nnapi/TypeUtils.h> #include <nnapi/Types.h> #include <nnapi/hal/1.0/Device.h> #include <functional> #include <memory> #include <string> namespace android::hardware::neuralnetworks::V1_0::utils { namespace { using ::testing::_; using ::testing::Invoke; using ::testing::InvokeWithoutArgs; const nn::Model kSimpleModel = { .main = {.operands = {{.type = nn::OperandType::TENSOR_FLOAT32, .dimensions = {1}, .lifetime = nn::Operand::LifeTime::SUBGRAPH_INPUT}, {.type = nn::OperandType::TENSOR_FLOAT32, .dimensions = {1}, .lifetime = nn::Operand::LifeTime::SUBGRAPH_OUTPUT}}, .operations = {{.type = nn::OperationType::RELU, .inputs = {0}, .outputs = {1}}}, .inputIndexes = {0}, .outputIndexes = {1}}}; const std::string kName = "Google-MockV1"; const std::string kInvalidName = ""; const sp<V1_0::IDevice> kInvalidDevice; constexpr V1_0::PerformanceInfo kNoPerformanceInfo = { .execTime = std::numeric_limits<float>::max(), .powerUsage = std::numeric_limits<float>::max()}; template <typename... Args> auto makeCallbackReturn(Args&&... args) { return [argPack = std::make_tuple(std::forward<Args>(args)...)](const auto& cb) { std::apply(cb, argPack); return Void(); }; } sp<MockDevice> createMockDevice() { const auto mockDevice = MockDevice::create(); // Setup default actions for each relevant call. const auto getCapabilities_ret = makeCallbackReturn( V1_0::ErrorStatus::NONE, V1_0::Capabilities{ .float32Performance = kNoPerformanceInfo, .quantized8Performance = kNoPerformanceInfo, }); // Setup default actions for each relevant call. ON_CALL(*mockDevice, getCapabilities(_)).WillByDefault(Invoke(getCapabilities_ret)); // These EXPECT_CALL(...).Times(testing::AnyNumber()) calls are to suppress warnings on the // uninteresting methods calls. EXPECT_CALL(*mockDevice, getCapabilities(_)).Times(testing::AnyNumber()); return mockDevice; } auto makePreparedModelReturn(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus, const sp<V1_0::utils::MockPreparedModel>& preparedModel) { return [launchStatus, returnStatus, preparedModel](const V1_0::Model& /*model*/, const sp<V1_0::IPreparedModelCallback>& cb) -> hardware::Return<V1_0::ErrorStatus> { cb->notify(returnStatus, preparedModel).isOk(); return launchStatus; }; } std::function<hardware::Status()> makeTransportFailure(status_t status) { return [status] { return hardware::Status::fromStatusT(status); }; } const auto makeGeneralTransportFailure = makeTransportFailure(NO_MEMORY); const auto makeDeadObjectFailure = makeTransportFailure(DEAD_OBJECT); } // namespace TEST(DeviceTest, invalidName) { // run test const auto device = MockDevice::create(); const auto result = Device::create(kInvalidName, device); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::INVALID_ARGUMENT); } TEST(DeviceTest, invalidDevice) { // run test const auto result = Device::create(kName, kInvalidDevice); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::INVALID_ARGUMENT); } TEST(DeviceTest, getCapabilitiesError) { // setup call const auto mockDevice = createMockDevice(); const auto ret = makeCallbackReturn(V1_0::ErrorStatus::GENERAL_FAILURE, V1_0::Capabilities{ .float32Performance = kNoPerformanceInfo, .quantized8Performance = kNoPerformanceInfo, }); EXPECT_CALL(*mockDevice, getCapabilities(_)).Times(1).WillOnce(Invoke(ret)); // run test const auto result = Device::create(kName, mockDevice); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, getCapabilitiesTransportFailure) { // setup call const auto mockDevice = createMockDevice(); EXPECT_CALL(*mockDevice, getCapabilities(_)) .Times(1) .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test const auto result = Device::create(kName, mockDevice); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, getCapabilitiesDeadObject) { // setup call const auto mockDevice = createMockDevice(); EXPECT_CALL(*mockDevice, getCapabilities(_)) .Times(1) .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); // run test const auto result = Device::create(kName, mockDevice); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT); } TEST(DeviceTest, linkToDeathError) { // setup call const auto mockDevice = createMockDevice(); const auto ret = []() -> Return<bool> { return false; }; EXPECT_CALL(*mockDevice, linkToDeathRet()).Times(1).WillOnce(InvokeWithoutArgs(ret)); // run test const auto result = Device::create(kName, mockDevice); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, linkToDeathTransportFailure) { // setup call const auto mockDevice = createMockDevice(); EXPECT_CALL(*mockDevice, linkToDeathRet()) .Times(1) .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test const auto result = Device::create(kName, mockDevice); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, linkToDeathDeadObject) { // setup call const auto mockDevice = createMockDevice(); EXPECT_CALL(*mockDevice, linkToDeathRet()) .Times(1) .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); // run test const auto result = Device::create(kName, mockDevice); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT); } TEST(DeviceTest, getName) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); // run test const auto& name = device->getName(); // verify result EXPECT_EQ(name, kName); } TEST(DeviceTest, getFeatureLevel) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); // run test const auto featureLevel = device->getFeatureLevel(); // verify result EXPECT_EQ(featureLevel, nn::Version::ANDROID_OC_MR1); } TEST(DeviceTest, getCachedData) { // setup call const auto mockDevice = createMockDevice(); const auto result = Device::create(kName, mockDevice); ASSERT_TRUE(result.has_value()) << "Failed with " << result.error().code << ": " << result.error().message; const auto& device = result.value(); // run test and verify results EXPECT_EQ(device->getVersionString(), device->getVersionString()); EXPECT_EQ(device->getType(), device->getType()); EXPECT_EQ(device->getSupportedExtensions(), device->getSupportedExtensions()); EXPECT_EQ(device->getNumberOfCacheFilesNeeded(), device->getNumberOfCacheFilesNeeded()); EXPECT_EQ(device->getCapabilities(), device->getCapabilities()); } TEST(DeviceTest, wait) { // setup call const auto mockDevice = createMockDevice(); const auto ret = []() -> Return<void> { return {}; }; EXPECT_CALL(*mockDevice, ping()).Times(1).WillOnce(InvokeWithoutArgs(ret)); const auto device = Device::create(kName, mockDevice).value(); // run test const auto result = device->wait(); // verify result ASSERT_TRUE(result.has_value()) << "Failed with " << result.error().code << ": " << result.error().message; } TEST(DeviceTest, waitTransportFailure) { // setup call const auto mockDevice = createMockDevice(); EXPECT_CALL(*mockDevice, ping()) .Times(1) .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); const auto device = Device::create(kName, mockDevice).value(); // run test const auto result = device->wait(); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, waitDeadObject) { // setup call const auto mockDevice = createMockDevice(); EXPECT_CALL(*mockDevice, ping()).Times(1).WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); const auto device = Device::create(kName, mockDevice).value(); // run test const auto result = device->wait(); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT); } TEST(DeviceTest, getSupportedOperations) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); const auto ret = [](const auto& model, const auto& cb) { cb(V1_0::ErrorStatus::NONE, std::vector<bool>(model.operations.size(), true)); return hardware::Void(); }; EXPECT_CALL(*mockDevice, getSupportedOperations(_, _)).Times(1).WillOnce(Invoke(ret)); // run test const auto result = device->getSupportedOperations(kSimpleModel); // verify result ASSERT_TRUE(result.has_value()) << "Failed with " << result.error().code << ": " << result.error().message; const auto& supportedOperations = result.value(); EXPECT_EQ(supportedOperations.size(), kSimpleModel.main.operations.size()); EXPECT_THAT(supportedOperations, Each(testing::IsTrue())); } TEST(DeviceTest, getSupportedOperationsError) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); const auto ret = [](const auto& /*model*/, const auto& cb) { cb(V1_0::ErrorStatus::GENERAL_FAILURE, {}); return hardware::Void(); }; EXPECT_CALL(*mockDevice, getSupportedOperations(_, _)).Times(1).WillOnce(Invoke(ret)); // run test const auto result = device->getSupportedOperations(kSimpleModel); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, getSupportedOperationsTransportFailure) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); EXPECT_CALL(*mockDevice, getSupportedOperations(_, _)) .Times(1) .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test const auto result = device->getSupportedOperations(kSimpleModel); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, getSupportedOperationsDeadObject) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); EXPECT_CALL(*mockDevice, getSupportedOperations(_, _)) .Times(1) .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); // run test const auto result = device->getSupportedOperations(kSimpleModel); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT); } TEST(DeviceTest, prepareModel) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); const auto mockPreparedModel = V1_0::utils::MockPreparedModel::create(); EXPECT_CALL(*mockDevice, prepareModel(_, _)) .Times(1) .WillOnce(Invoke(makePreparedModelReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, mockPreparedModel))); // run test const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT, nn::Priority::DEFAULT, {}, {}, {}, {}); // verify result ASSERT_TRUE(result.has_value()) << "Failed with " << result.error().code << ": " << result.error().message; EXPECT_NE(result.value(), nullptr); } TEST(DeviceTest, prepareModelLaunchError) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); EXPECT_CALL(*mockDevice, prepareModel(_, _)) .Times(1) .WillOnce(Invoke(makePreparedModelReturn(V1_0::ErrorStatus::GENERAL_FAILURE, V1_0::ErrorStatus::GENERAL_FAILURE, nullptr))); // run test const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT, nn::Priority::DEFAULT, {}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, prepareModelReturnError) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); EXPECT_CALL(*mockDevice, prepareModel(_, _)) .Times(1) .WillOnce(Invoke(makePreparedModelReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE, nullptr))); // run test const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT, nn::Priority::DEFAULT, {}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, prepareModelNullptrError) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); EXPECT_CALL(*mockDevice, prepareModel(_, _)) .Times(1) .WillOnce(Invoke(makePreparedModelReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, nullptr))); // run test const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT, nn::Priority::DEFAULT, {}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, prepareModelTransportFailure) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); EXPECT_CALL(*mockDevice, prepareModel(_, _)) .Times(1) .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); // run test const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT, nn::Priority::DEFAULT, {}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, prepareModelDeadObject) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); EXPECT_CALL(*mockDevice, prepareModel(_, _)) .Times(1) .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); // run test const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT, nn::Priority::DEFAULT, {}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT); } TEST(DeviceTest, prepareModelAsyncCrash) { // setup test const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); const auto ret = [&mockDevice]() -> hardware::Return<V1_0::ErrorStatus> { mockDevice->simulateCrash(); return V1_0::ErrorStatus::NONE; }; EXPECT_CALL(*mockDevice, prepareModel(_, _)).Times(1).WillOnce(InvokeWithoutArgs(ret)); // run test const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT, nn::Priority::DEFAULT, {}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT); } TEST(DeviceTest, prepareModelFromCacheNotSupported) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); // run test const auto result = device->prepareModelFromCache({}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } TEST(DeviceTest, allocateNotSupported) { // setup call const auto mockDevice = createMockDevice(); const auto device = Device::create(kName, mockDevice).value(); // run test const auto result = device->allocate({}, {}, {}, {}); // verify result ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE); } } // namespace android::hardware::neuralnetworks::V1_0::utils
neuralnetworks/1.0/utils/test/MockDevice.h 0 → 100644 +86 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_DEVICE #define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_DEVICE #include <android/hardware/neuralnetworks/1.0/IDevice.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <hidl/Status.h> namespace android::hardware::neuralnetworks::V1_0::utils { class MockDevice final : public IDevice { public: static sp<MockDevice> create(); // IBase methods below. MOCK_METHOD(Return<void>, ping, (), (override)); MOCK_METHOD(Return<bool>, linkToDeathRet, ()); Return<bool> linkToDeath(const sp<hidl_death_recipient>& recipient, uint64_t /*cookie*/); // V1_0 methods below. MOCK_METHOD(Return<void>, getCapabilities, (getCapabilities_cb cb), (override)); MOCK_METHOD(Return<void>, getSupportedOperations, (const V1_0::Model& model, getSupportedOperations_cb cb), (override)); MOCK_METHOD(Return<V1_0::ErrorStatus>, prepareModel, (const V1_0::Model& model, const sp<V1_0::IPreparedModelCallback>& callback), (override)); MOCK_METHOD(Return<V1_0::DeviceStatus>, getStatus, (), (override)); // Helper methods. void simulateCrash(); private: sp<hidl_death_recipient> mDeathRecipient; }; inline sp<MockDevice> MockDevice::create() { auto mockDevice = sp<MockDevice>::make(); // Setup default actions for each relevant call. const auto ret = []() -> Return<bool> { return true; }; // Setup default actions for each relevant call. ON_CALL(*mockDevice, linkToDeathRet()).WillByDefault(testing::Invoke(ret)); // These EXPECT_CALL(...).Times(testing::AnyNumber()) calls are to suppress warnings on the // uninteresting methods calls. EXPECT_CALL(*mockDevice, linkToDeathRet()).Times(testing::AnyNumber()); return mockDevice; } inline Return<bool> MockDevice::linkToDeath(const sp<hidl_death_recipient>& recipient, uint64_t /*cookie*/) { mDeathRecipient = recipient; return linkToDeathRet(); } inline void MockDevice::simulateCrash() { ASSERT_NE(nullptr, mDeathRecipient.get()); // Currently, the utils::Device will not use the `cookie` or `who` arguments, so we pass in 0 // and nullptr for these arguments instead. Normally, they are used by the hidl_death_recipient // to determine which object is dead. However, the utils::Device code only pairs a single death // recipient with a single HIDL interface object, so these arguments are redundant. mDeathRecipient->serviceDied(0, nullptr); } } // namespace android::hardware::neuralnetworks::V1_0::utils #endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_DEVICE