From 5591a18ea83233a6fd41366da16acdc3028cc7f1 Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Sat, 7 Sep 2019 15:16:51 -0700 Subject: Simplify IDevice reboot logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HIDL allows a service to be retrieved with two functions: * ::getService — blocks until service is retrieved * ::tryGetService — immediately returns service or nullptr Currently, the NN runtime retrieves the service in three different places: 1) When the runtime first starts, ::getService is used to acquire all services 2) When the object is dead, ::tryGetService is used to attempt to reacquire the service, but will quickly resume if the service is still rebooting 3) When the client calls ANNDevice_wait, ::getService is used to block until the service is active again This CL simplifies the IDevice reboot logic by changing these static class functions to dependency injection. Specifically, VersionedIDevice now retrieves a handle to the IDevice object through a DeviceFactory function that is passed in when the VersionedIDevice object is created. This function can either operate as blocking or nonblocking to support all use-cases described above, and makes it easier to test the VersionedIDevice recovery code. Bug: 139189546 Test: mma Test: NeuralNetworksTest_static Test: CtsNNAPITestCases Change-Id: I012eb4df6f09f98bdfbd0835457ba98bc22d906e --- nn/common/include/HalInterfaces.h | 1 + nn/runtime/Manager.cpp | 37 +++++++++++++++++++------------------ nn/runtime/Manager.h | 5 +++-- nn/runtime/Memory.cpp | 2 +- nn/runtime/VersionedInterfaces.cpp | 22 ++++++++++++++++------ nn/runtime/VersionedInterfaces.h | 13 +++++++++---- 6 files changed, 49 insertions(+), 31 deletions(-) (limited to 'nn') diff --git a/nn/common/include/HalInterfaces.h b/nn/common/include/HalInterfaces.h index fe1ff563e..4e3a3800b 100644 --- a/nn/common/include/HalInterfaces.h +++ b/nn/common/include/HalInterfaces.h @@ -103,6 +103,7 @@ using OperandExtraParams = V1_2::Operand::ExtraParams; using CacheToken = hardware::hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +using DeviceFactory = std::function(bool blocking)>; using ModelFactory = std::function; inline constexpr Priority kDefaultPriority = Priority::MEDIUM; diff --git a/nn/runtime/Manager.cpp b/nn/runtime/Manager.cpp index 7be8419ad..310710e3c 100644 --- a/nn/runtime/Manager.cpp +++ b/nn/runtime/Manager.cpp @@ -55,9 +55,10 @@ const Timing kNoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX // A Device with actual underlying driver class DriverDevice : public Device { public: - // Create a DriverDevice from a name and an IDevice. + // Create a DriverDevice from a name and a DeviceFactory function. // Returns nullptr on failure. - static std::shared_ptr create(std::string name, sp device); + static std::shared_ptr create(const std::string& name, + const DeviceFactory& makeDevice); // Prefer using DriverDevice::create DriverDevice(std::shared_ptr device); @@ -159,6 +160,7 @@ class DriverPreparedModel : public PreparedModel { DriverDevice::DriverDevice(std::shared_ptr device) : kInterface(std::move(device)) { + CHECK(kInterface != nullptr); #ifdef NN_DEBUGGABLE static const char samplePrefix[] = "sample"; if (getName().substr(0, sizeof(samplePrefix) - 1) == samplePrefix) { @@ -167,17 +169,17 @@ DriverDevice::DriverDevice(std::shared_ptr device) #endif // NN_DEBUGGABLE } -std::shared_ptr DriverDevice::create(std::string name, sp device) { - CHECK(device != nullptr); - std::shared_ptr versionedDevice = - VersionedIDevice::create(name, std::move(device)); - if (versionedDevice == nullptr) { +std::shared_ptr DriverDevice::create(const std::string& name, + const DeviceFactory& makeDevice) { + CHECK(makeDevice != nullptr); + std::shared_ptr device = VersionedIDevice::create(name, makeDevice); + if (device == nullptr) { LOG(ERROR) << "DriverDevice::create failed to create VersionedIDevice object for service " << name; return nullptr; } - return std::make_shared(std::move(versionedDevice)); + return std::make_shared(std::move(device)); } std::vector DriverDevice::getSupportedOperations(const MetaModel& metaModel) const { @@ -817,7 +819,8 @@ std::shared_ptr DeviceManager::getCpuDevice() { std::shared_ptr DeviceManager::forTest_makeDriverDevice(const std::string& name, const sp& device) { - const auto driverDevice = DriverDevice::create(name, device); + const DeviceFactory makeDevice = [device](bool /*blocking*/) { return device; }; + const auto driverDevice = DriverDevice::create(name, makeDevice); CHECK(driverDevice != nullptr); return driverDevice; } @@ -829,12 +832,10 @@ void DeviceManager::findAvailableDevices() { const auto names = hardware::getAllHalInstanceNames(V1_0::IDevice::descriptor); for (const auto& name : names) { VLOG(MANAGER) << "Found interface " << name; - sp device = V1_0::IDevice::getService(name); - if (device == nullptr) { - LOG(ERROR) << "Got a null IDEVICE for " << name; - continue; - } - registerDevice(name, device); + const DeviceFactory makeDevice = [name](bool blocking) { + return blocking ? V1_0::IDevice::getService(name) : V1_0::IDevice::tryGetService(name); + }; + registerDevice(name, makeDevice); } // register CPU fallback device @@ -842,9 +843,9 @@ void DeviceManager::findAvailableDevices() { mDevicesCpuOnly.push_back(CpuDevice::get()); } -void DeviceManager::registerDevice(const std::string& name, const sp& device) { - if (const auto d = DriverDevice::create(name, device)) { - mDevices.push_back(d); +void DeviceManager::registerDevice(const std::string& name, const DeviceFactory& makeDevice) { + if (auto device = DriverDevice::create(name, makeDevice)) { + mDevices.push_back(std::move(device)); } } diff --git a/nn/runtime/Manager.h b/nn/runtime/Manager.h index c28ee49a6..d6d483576 100644 --- a/nn/runtime/Manager.h +++ b/nn/runtime/Manager.h @@ -169,7 +169,8 @@ class DeviceManager { // Register a test device. void forTest_registerDevice(const std::string& name, const sp& device) { - registerDevice(name, device); + const hal::DeviceFactory makeDevice = [device](bool /*blocking*/) { return device; }; + registerDevice(name, makeDevice); } // Re-initialize the list of available devices. @@ -192,7 +193,7 @@ class DeviceManager { DeviceManager(); // Adds a device for the manager to use. - void registerDevice(const std::string& name, const sp& device); + void registerDevice(const std::string& name, const hal::DeviceFactory& makeDevice); void findAvailableDevices(); diff --git a/nn/runtime/Memory.cpp b/nn/runtime/Memory.cpp index 7bfaf5562..e0bd6b953 100644 --- a/nn/runtime/Memory.cpp +++ b/nn/runtime/Memory.cpp @@ -194,7 +194,7 @@ Memory::Memory(sp buffer, uint32_t token) : kBuffer(std::move(buffer)), kToken(token) {} Memory::~Memory() { - for (const auto [ptr, weakBurst] : mUsedBy) { + for (const auto& [ptr, weakBurst] : mUsedBy) { if (const std::shared_ptr burst = weakBurst.lock()) { burst->freeMemory(getKey()); } diff --git a/nn/runtime/VersionedInterfaces.cpp b/nn/runtime/VersionedInterfaces.cpp index cd39a52a7..3ae950eac 100644 --- a/nn/runtime/VersionedInterfaces.cpp +++ b/nn/runtime/VersionedInterfaces.cpp @@ -703,8 +703,16 @@ std::optional initialize(const Core& core) { } std::shared_ptr VersionedIDevice::create(std::string serviceName, - sp device) { - CHECK(device != nullptr) << "VersionedIDevice::create passed invalid device object."; + const DeviceFactory& makeDevice) { + CHECK(makeDevice != nullptr) + << "VersionedIDevice::create passed invalid device factory object."; + + // get handle to IDevice object + sp device = makeDevice(/*blocking=*/true); + if (device == nullptr) { + VLOG(DRIVER) << "VersionedIDevice::create got a null IDevice for " << serviceName; + return nullptr; + } auto core = Core::create(std::move(device)); if (!core.has_value()) { @@ -722,20 +730,22 @@ std::shared_ptr VersionedIDevice::create(std::string serviceNa std::move(*initialData); return std::make_shared( std::move(capabilities), std::move(supportedExtensions), type, std::move(versionString), - numberOfCacheFilesNeeded, std::move(serviceName), std::move(core.value())); + numberOfCacheFilesNeeded, std::move(serviceName), makeDevice, std::move(core.value())); } VersionedIDevice::VersionedIDevice(hal::Capabilities capabilities, std::vector supportedExtensions, int32_t type, std::string versionString, std::pair numberOfCacheFilesNeeded, - std::string serviceName, Core core) + std::string serviceName, const DeviceFactory& makeDevice, + Core core) : kCapabilities(std::move(capabilities)), kSupportedExtensions(std::move(supportedExtensions)), kType(type), kVersionString(std::move(versionString)), kNumberOfCacheFilesNeeded(numberOfCacheFilesNeeded), kServiceName(std::move(serviceName)), + kMakeDevice(makeDevice), mCore(std::move(core)) {} std::optional VersionedIDevice::Core::create(sp device) { @@ -874,7 +884,7 @@ Return VersionedIDevice::recoverable( if (pingReturn.isDeadObject()) { VLOG(DRIVER) << "VersionedIDevice::recoverable(" << context << ") -- Recovering " << kServiceName; - sp recoveredDevice = V1_0::IDevice::tryGetService(kServiceName); + sp recoveredDevice = kMakeDevice(/*blocking=*/false); if (recoveredDevice == nullptr) { VLOG(DRIVER) << "VersionedIDevice::recoverable got a null IDEVICE for " << kServiceName; @@ -911,7 +921,7 @@ int VersionedIDevice::wait() const { auto pingReturn = mCore.getDevice()->ping(); if (pingReturn.isDeadObject()) { VLOG(DRIVER) << "VersionedIDevice::wait -- Recovering " << kServiceName; - sp recoveredDevice = V1_0::IDevice::getService(kServiceName); + sp recoveredDevice = kMakeDevice(/*blocking=*/true); if (recoveredDevice == nullptr) { LOG(ERROR) << "VersionedIDevice::wait got a null IDevice for " << kServiceName; return ANEURALNETWORKS_OP_FAILED; diff --git a/nn/runtime/VersionedInterfaces.h b/nn/runtime/VersionedInterfaces.h index 94ca3fe49..efde0bdf5 100644 --- a/nn/runtime/VersionedInterfaces.h +++ b/nn/runtime/VersionedInterfaces.h @@ -72,12 +72,12 @@ class VersionedIDevice { * protections. * * @param serviceName The name of the service that provides "device". - * @param device A device object that is at least version 1.0 of the IDevice - * interface. + * @param makeDevice A device factory function that returns a device object + * that is at least version 1.0 of the IDevice interface. * @return A valid VersionedIDevice object, otherwise nullptr. */ static std::shared_ptr create(std::string serviceName, - sp device); + const hal::DeviceFactory& makeDevice); /** * Constructor for the VersionedIDevice object. @@ -92,6 +92,8 @@ class VersionedIDevice { * @param numberOfCacheFilesNeeded Number of model cache and data cache * files needed by the driver. * @param serviceName The name of the service that provides core.getDevice(). + * @param makeDevice A device factory function that returns a device object + * that is at least version 1.0 of the IDevice interface. * @param core An object that encapsulates a V1_0::IDevice, any appropriate downcasts to * newer interfaces, and a hidl_death_recipient that will proactively handle * the case when the service containing the IDevice object crashes. @@ -100,7 +102,7 @@ class VersionedIDevice { std::vector supportedExtensions, int32_t type, std::string versionString, std::pair numberOfCacheFilesNeeded, - std::string serviceName, Core core); + std::string serviceName, const hal::DeviceFactory& makeDevice, Core core); /** * Gets the capabilities of a driver. @@ -554,6 +556,9 @@ class VersionedIDevice { // The name of the service that implements the driver. const std::string kServiceName; + // Factory function object to generate an IDevice object. + const hal::DeviceFactory kMakeDevice; + // Guards access to mCore. mutable std::shared_mutex mMutex; -- cgit v1.2.3 From 56443eb92c61db057948394493d6a5a237d68de7 Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Thu, 22 Aug 2019 00:38:32 -0700 Subject: Create tests for VersionedInterfaces errors This CL introduces the following kinds of tests: * device creation and initialization errors * "normal" functional positive and negative tests * HIDL transport error tests * mock service crash tests Fixes: 139189546 Bug: 129572750 Test: mma Test: atest NeuralNetworksTest_static Change-Id: I3e1eb5433732695572044a74f1529ffc9c3a1982 --- nn/runtime/test/Android.bp | 4 + nn/runtime/test/TestVersionedInterfaces.cpp | 2916 +++++++++++++++++++++++++++ 2 files changed, 2920 insertions(+) create mode 100644 nn/runtime/test/TestVersionedInterfaces.cpp (limited to 'nn') diff --git a/nn/runtime/test/Android.bp b/nn/runtime/test/Android.bp index 8874eee69..d8e0b4ce3 100644 --- a/nn/runtime/test/Android.bp +++ b/nn/runtime/test/Android.bp @@ -131,6 +131,7 @@ cc_defaults { "TestPartitioning.cpp", "TestPartitioningRandom.cpp", "TestRemoveDefaultArguments.cpp", + "TestVersionedInterfaces.cpp", "fibonacci_extension/FibonacciDriver.cpp", "fibonacci_extension/FibonacciExtensionTest.cpp", @@ -140,7 +141,9 @@ cc_defaults { ], static_libs: [ "android.hardware.neuralnetworks@1.0-adapter-helper", + "android.hardware.neuralnetworks@1.1-adapter-helper", "android.hardware.neuralnetworks@1.2-adapter-helper", + "android.hardware.neuralnetworks@1.3-adapter-helper", "libSampleDriver", "libgmock", "libhidladapter", @@ -153,6 +156,7 @@ cc_defaults { ], header_libs: [ "libneuralnetworks_private_headers", + "libutils_headers", "neuralnetworks_example_fibonacci_extension", ], } diff --git a/nn/runtime/test/TestVersionedInterfaces.cpp b/nn/runtime/test/TestVersionedInterfaces.cpp new file mode 100644 index 000000000..6d1306d57 --- /dev/null +++ b/nn/runtime/test/TestVersionedInterfaces.cpp @@ -0,0 +1,2916 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "HalInterfaces.h" +#include "MemoryUtils.h" +#include "MetaModel.h" +#include "VersionedInterfaces.h" + +namespace android::nn { +namespace { + +using namespace hal; +using testing::_; +using testing::Invoke; +using testing::InvokeWithoutArgs; +using testing::MockFunction; +using MockDeviceFactory = MockFunction(bool blocking)>; + +constexpr uint32_t kNoCacheFilesNeeded = 0; +constexpr uint32_t kMaxNumberOfCacheFiles = + static_cast(Constant::MAX_NUMBER_OF_CACHE_FILES); +constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits::max(), + .timeInDriver = std::numeric_limits::max()}; + +template +auto makeCallbackReturn(Args&&... args) { + return [argPack = std::make_tuple(std::forward(args)...)](const auto& cb) { + std::apply(cb, argPack); + return Void(); + }; +}; + +class MockDevice : public IDevice { + public: + static sp create() { + const sp mockDevice = new MockDevice(); + + const auto linkToDeathRet_ret = []() -> Return { return true; }; + const auto getCapabilities_ret = + makeCallbackReturn(V1_0::ErrorStatus::NONE, V1_0::Capabilities{}); + const auto getCapabilities_1_1_ret = + makeCallbackReturn(V1_0::ErrorStatus::NONE, V1_1::Capabilities{}); + const auto getVersionString_ret = + makeCallbackReturn(V1_0::ErrorStatus::NONE, "Google-MockV1"); + const auto getType_ret = makeCallbackReturn(V1_0::ErrorStatus::NONE, DeviceType::OTHER); + const auto getCapabilities_1_2_ret = + makeCallbackReturn(V1_0::ErrorStatus::NONE, V1_2::Capabilities{}); + const auto getSupportedExtensions_ret = + makeCallbackReturn(V1_0::ErrorStatus::NONE, hidl_vec{}); + const auto getNumberOfCacheFilesNeeded_ret = makeCallbackReturn( + V1_0::ErrorStatus::NONE, kMaxNumberOfCacheFiles, kMaxNumberOfCacheFiles); + const auto getCapabilities_1_3_ret = + makeCallbackReturn(V1_3::ErrorStatus::NONE, V1_3::Capabilities{}); + + ON_CALL(*mockDevice, linkToDeathRet()).WillByDefault(Invoke(linkToDeathRet_ret)); + ON_CALL(*mockDevice, getCapabilities(_)).WillByDefault(Invoke(getCapabilities_ret)); + ON_CALL(*mockDevice, getCapabilities_1_1(_)).WillByDefault(Invoke(getCapabilities_1_1_ret)); + ON_CALL(*mockDevice, getVersionString(_)).WillByDefault(Invoke(getVersionString_ret)); + ON_CALL(*mockDevice, getType(_)).WillByDefault(Invoke(getType_ret)); + ON_CALL(*mockDevice, getCapabilities_1_2(_)).WillByDefault(Invoke(getCapabilities_1_2_ret)); + ON_CALL(*mockDevice, getSupportedExtensions(_)) + .WillByDefault(Invoke(getSupportedExtensions_ret)); + ON_CALL(*mockDevice, getNumberOfCacheFilesNeeded(_)) + .WillByDefault(Invoke(getNumberOfCacheFilesNeeded_ret)); + ON_CALL(*mockDevice, getCapabilities_1_3(_)).WillByDefault(Invoke(getCapabilities_1_3_ret)); + + // These EXPECT_CALL(...).Times(testing::AnyNumber()) calls are to + // suppress warnings on the uninteresting methods calls. + EXPECT_CALL(*mockDevice, linkToDeathRet()).Times(testing::AnyNumber()); + EXPECT_CALL(*mockDevice, getCapabilities(_)).Times(testing::AnyNumber()); + EXPECT_CALL(*mockDevice, getCapabilities_1_1(_)).Times(testing::AnyNumber()); + EXPECT_CALL(*mockDevice, getVersionString(_)).Times(testing::AnyNumber()); + EXPECT_CALL(*mockDevice, getType(_)).Times(testing::AnyNumber()); + EXPECT_CALL(*mockDevice, getCapabilities_1_2(_)).Times(testing::AnyNumber()); + EXPECT_CALL(*mockDevice, getSupportedExtensions(_)).Times(testing::AnyNumber()); + EXPECT_CALL(*mockDevice, getNumberOfCacheFilesNeeded(_)).Times(testing::AnyNumber()); + EXPECT_CALL(*mockDevice, getCapabilities_1_3(_)).Times(testing::AnyNumber()); + + return mockDevice; + } + + // IBase methods below. + Return linkToDeath(const sp& recipient, + uint64_t /*cookie*/) override { + mDeathRecipient = recipient; + return linkToDeathRet(); + } + MOCK_METHOD(Return, ping, (), (override)); + + // V1_0 methods below. + MOCK_METHOD(Return, getCapabilities, (getCapabilities_cb cb), (override)); + MOCK_METHOD(Return, getSupportedOperations, + (const V1_0::Model& model, getSupportedOperations_cb cb), (override)); + MOCK_METHOD(Return, prepareModel, + (const V1_0::Model& model, const sp& callback), + (override)); + MOCK_METHOD(Return, getStatus, (), (override)); + + // V1_1 methods below. + MOCK_METHOD(Return, getCapabilities_1_1, (getCapabilities_1_1_cb cb), (override)); + MOCK_METHOD(Return, getSupportedOperations_1_1, + (const V1_1::Model& model, getSupportedOperations_1_1_cb cb), (override)); + MOCK_METHOD(Return, prepareModel_1_1, + (const V1_1::Model& model, ExecutionPreference preference, + const sp& callback), + (override)); + + // V1_2 methods below. + MOCK_METHOD(Return, getVersionString, (getVersionString_cb cb), (override)); + MOCK_METHOD(Return, getType, (getType_cb cb), (override)); + MOCK_METHOD(Return, getCapabilities_1_2, (getCapabilities_1_2_cb cb), (override)); + MOCK_METHOD(Return, getSupportedExtensions, (getSupportedExtensions_cb cb), (override)); + MOCK_METHOD(Return, getSupportedOperations_1_2, + (const V1_2::Model& model, getSupportedOperations_1_2_cb cb), (override)); + MOCK_METHOD(Return, getNumberOfCacheFilesNeeded, (getNumberOfCacheFilesNeeded_cb cb), + (override)); + MOCK_METHOD(Return, prepareModel_1_2, + (const V1_2::Model& model, ExecutionPreference preference, + const hidl_vec& modelCache, const hidl_vec& dataCache, + const CacheToken& token, const sp& callback), + (override)); + MOCK_METHOD(Return, prepareModelFromCache, + (const hidl_vec& modelCache, const hidl_vec& dataCache, + const CacheToken& token, const sp& callback), + (override)); + + // V1_3 methods below. + MOCK_METHOD(Return, getCapabilities_1_3, (getCapabilities_1_3_cb cb), (override)); + MOCK_METHOD(Return, getSupportedOperations_1_3, + (const V1_3::Model& model, getSupportedOperations_1_3_cb cb), (override)); + MOCK_METHOD(Return, prepareModel_1_3, + (const V1_3::Model& model, ExecutionPreference preference, Priority priority, + const OptionalTimePoint& deadline, const hidl_vec& modelCache, + const hidl_vec& dataCache, const CacheToken& token, + const sp& callback), + (override)); + MOCK_METHOD(Return, prepareModelFromCache_1_3, + (const OptionalTimePoint& deadline, const hidl_vec& modelCache, + const hidl_vec& dataCache, const CacheToken& token, + const sp& callback), + (override)); + MOCK_METHOD(Return, allocate, + (const BufferDesc& desc, const hidl_vec>& preparedModels, + const hidl_vec& inputRoles, const hidl_vec& outputRoles, + allocate_cb cb), + (override)); + + // Helper methods. + MOCK_METHOD(Return, linkToDeathRet, ()); + void simulateCrash() { + ASSERT_NE(nullptr, mDeathRecipient.get()); + + // Currently, the VersionedInterfaces code 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 VersionedInterfaces + // code only pairs a single death recipient with a single HIDL + // interface object, so these arguments are redundant. + mDeathRecipient->serviceDied(0, nullptr); + } + + private: + // Members. + sp mDeathRecipient; +}; + +class MockPreparedModel : public IPreparedModel { + public: + static sp create() { + const sp mockPreparedModel = new MockPreparedModel(); + + const auto linkToDeathRet_ret = []() -> Return { return true; }; + ON_CALL(*mockPreparedModel, linkToDeathRet()).WillByDefault(Invoke(linkToDeathRet_ret)); + + // This EXPECT_CALL(...).Times(testing::AnyNumber()) calls are to + // suppress warnings on the uninteresting methods calls. + EXPECT_CALL(*mockPreparedModel, linkToDeathRet()).Times(testing::AnyNumber()); + + return mockPreparedModel; + } + + // IBase methods below. + Return linkToDeath(const sp& recipient, + uint64_t /*cookie*/) override { + mDeathRecipient = recipient; + return linkToDeathRet(); + } + MOCK_METHOD(Return, ping, (), (override)); + + // V1_0 methods below. + MOCK_METHOD(Return, execute, + (const V1_0::Request& request, const sp& callback), + (override)); + + // V1_2 methods below. + MOCK_METHOD(Return, execute_1_2, + (const V1_0::Request& request, MeasureTiming measure, + const sp& callback), + (override)); + MOCK_METHOD(Return, executeSynchronously, + (const V1_0::Request& request, MeasureTiming measure, executeSynchronously_cb cb), + (override)); + MOCK_METHOD(Return, configureExecutionBurst, + (const sp& callback, + const hardware::MQDescriptorSync& requestChannel, + const hardware::MQDescriptorSync& resultChannel, + configureExecutionBurst_cb cb), + (override)); + + // V1_3 methods below. + MOCK_METHOD(Return, execute_1_3, + (const V1_3::Request& request, MeasureTiming measure, + const OptionalTimePoint& deadline, + const OptionalTimeoutDuration& loopTimeoutDuration, + const sp& callback), + (override)); + MOCK_METHOD(Return, executeSynchronously_1_3, + (const V1_3::Request& request, MeasureTiming measure, + const OptionalTimePoint& deadline, + const OptionalTimeoutDuration& loopTimeoutDuration, + executeSynchronously_1_3_cb cb), + (override)); + MOCK_METHOD(Return, executeFenced, + (const V1_3::Request& request, const hidl_vec& waitFor, + MeasureTiming measure, const OptionalTimePoint& deadline, + const OptionalTimeoutDuration& loopTimeoutDuration, + const OptionalTimeoutDuration& duration, executeFenced_cb cb), + (override)); + + // Helper methods. + MOCK_METHOD(Return, linkToDeathRet, ()); + void simulateCrash() { + ASSERT_NE(nullptr, mDeathRecipient.get()); + + // Currently, the VersionedInterfaces code 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 VersionedInterfaces + // code only pairs a single death recipient with a single HIDL + // interface object, so these arguments are redundant. + mDeathRecipient->serviceDied(0, nullptr); + } + + private: + // Members. + sp mDeathRecipient; +}; + +class MockBurstContext : public V1_2::IBurstContext { + public: + // V1_2 methods below. + MOCK_METHOD(Return, freeMemory, (int32_t slot), (override)); +}; + +class MockFencedExecutionCallback : public IFencedExecutionCallback { + public: + // V1_3 methods below. + MOCK_METHOD(Return, getExecutionInfo, (getExecutionInfo_cb cb), (override)); +}; + +class MockBuffer : public IBuffer { + public: + // V1_3 methods below. + MOCK_METHOD(Return, copyTo, (const hidl_memory& dst), (override)); + MOCK_METHOD(Return, copyFrom, + (const hidl_memory& src, const hidl_vec& dimensions), (override)); +}; + +enum class Version { V1_0, V1_1, V1_2, V1_3, MOCK }; + +sp adaptAs(const sp& mockDevice, Version version) { + switch (version) { + case Version::V1_0: + return new V1_0::ADevice(mockDevice); + case Version::V1_1: + return new V1_1::ADevice(mockDevice); + case Version::V1_2: + return new V1_2::ADevice(mockDevice); + case Version::V1_3: + return new V1_3::ADevice(mockDevice); + case Version::MOCK: + return mockDevice; + } + LOG(FATAL) << "unrecognized version: " << static_cast(version); + return nullptr; +} + +auto makePreparedModelReturn(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus, + const sp& preparedModel) { + return [launchStatus, returnStatus, preparedModel]( + const V1_0::Model& /*model*/, + const sp& cb) -> Return { + cb->notify(returnStatus, preparedModel).isOk(); + return launchStatus; + }; +} +auto makePreparedModel_1_1Return(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus, + const sp& preparedModel) { + return [launchStatus, returnStatus, preparedModel]( + const V1_1::Model& /*model*/, ExecutionPreference /*preference*/, + const sp& cb) -> Return { + cb->notify(returnStatus, preparedModel).isOk(); + return launchStatus; + }; +} +auto makePreparedModel_1_2Return(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus, + const sp& preparedModel) { + return [launchStatus, returnStatus, preparedModel]( + const V1_2::Model& /*model*/, ExecutionPreference /*preference*/, + const auto& /*modelCache*/, const auto& /*dataCache*/, const auto& /*token*/, + const sp& cb) -> Return { + cb->notify_1_2(returnStatus, preparedModel).isOk(); + return launchStatus; + }; +} +auto makePreparedModel_1_3Return(V1_3::ErrorStatus launchStatus, V1_3::ErrorStatus returnStatus, + const sp& preparedModel) { + return [launchStatus, returnStatus, preparedModel]( + const V1_3::Model& /*model*/, ExecutionPreference /*preference*/, + Priority /*priority*/, const OptionalTimePoint& /*deadline*/, + const hidl_vec& /*modelCache*/, + const hidl_vec& /*dataCache*/, const CacheToken& /*token*/, + const sp& cb) -> Return { + cb->notify_1_3(returnStatus, preparedModel).isOk(); + return launchStatus; + }; +} + +auto makeExecuteReturn(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus) { + return [launchStatus, returnStatus]( + const V1_0::Request& /*request*/, + const sp& cb) -> Return { + cb->notify(returnStatus); + return launchStatus; + }; +} +auto makeExecute_1_2Return(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus, + const std::vector& outputShapes, const Timing& timing) { + return [launchStatus, returnStatus, outputShapes, timing]( + const V1_0::Request& /*request*/, MeasureTiming /*measureTiming*/, + const sp& cb) -> Return { + cb->notify_1_2(returnStatus, outputShapes, timing); + return launchStatus; + }; +} +auto makeExecute_1_3Return(V1_3::ErrorStatus launchStatus, V1_3::ErrorStatus returnStatus, + const std::vector& outputShapes, const Timing& timing) { + return [launchStatus, returnStatus, outputShapes, timing]( + const V1_3::Request& /*request*/, MeasureTiming /*measureTiming*/, + const OptionalTimePoint& /*deadline*/, + const OptionalTimeoutDuration& /*loopTimeoutDuration*/, + const sp& cb) -> Return { + cb->notify_1_3(returnStatus, outputShapes, timing); + return launchStatus; + }; +} +auto makeExecuteSynchronouslyReturn(V1_0::ErrorStatus status, + const std::vector& outputShapes, + const Timing& timing) { + return [status, outputShapes, timing](const V1_0::Request& /*request*/, + MeasureTiming /*measureTiming*/, + const V1_2::IPreparedModel::executeSynchronously_cb& cb) { + cb(status, outputShapes, timing); + return Void(); + }; +} +auto makeExecuteSynchronously_1_3Return(V1_3::ErrorStatus status, + const std::vector& outputShapes, + const Timing& timing) { + return [status, outputShapes, timing]( + const V1_3::Request& /*request*/, MeasureTiming /*measureTiming*/, + const OptionalTimePoint& /*deadline*/, + const OptionalTimeoutDuration& /*loopTimeoutDuration*/, + const V1_3::IPreparedModel::executeSynchronously_1_3_cb& cb) { + cb(status, outputShapes, timing); + return Void(); + }; +} +auto makeConfigureExecutionBurst(V1_0::ErrorStatus status, + const sp& burstContext) { + return [status, burstContext]( + const sp& /*callback*/, + const hardware::MQDescriptorSync& /*requestChannel*/, + const hardware::MQDescriptorSync& /*resultChannel*/, + V1_2::IPreparedModel::configureExecutionBurst_cb cb) { + cb(status, burstContext); + return Void(); + }; +} +auto makeExecuteFencedReturn(V1_3::ErrorStatus status, const hidl_handle& syncFence, + const sp& dispatchCallback) { + return [status, syncFence, dispatchCallback]( + const V1_3::Request& /*request*/, const hidl_vec& /*waitFor*/, + MeasureTiming /*measure*/, const OptionalTimePoint& /*deadline*/, + const OptionalTimeoutDuration& /*loopTimeoutDuration*/, + const OptionalTimeoutDuration& /*duration*/, + V1_3::IPreparedModel::executeFenced_cb cb) { + cb(status, syncFence, dispatchCallback); + return Void(); + }; +} + +// TODO: The "setupInitializationExpectation*" calls below re-specify the +// number of expected times each initialization method is called. Because +// this was originally set to `testing::AnyNumber()` when the object was +// created, do these calls act as no-ops, do they override the previous +// expectations, or are both expectations still active? + +void setupInitializationExpectationsV1_0(const sp& mockDevice) { + EXPECT_CALL(*mockDevice, getCapabilities_1_1(_)).Times(0); + EXPECT_CALL(*mockDevice, getCapabilities_1_2(_)).Times(0); + EXPECT_CALL(*mockDevice, getCapabilities_1_3(_)).Times(0); + EXPECT_CALL(*mockDevice, getVersionString(_)).Times(0); + EXPECT_CALL(*mockDevice, getType(_)).Times(0); + EXPECT_CALL(*mockDevice, getSupportedExtensions(_)).Times(0); + EXPECT_CALL(*mockDevice, getNumberOfCacheFilesNeeded(_)).Times(0); +} + +void setupInitializationExpectationsV1_1(const sp& mockDevice) { + EXPECT_CALL(*mockDevice, getCapabilities(_)).Times(0); + EXPECT_CALL(*mockDevice, getCapabilities_1_2(_)).Times(0); + EXPECT_CALL(*mockDevice, getCapabilities_1_3(_)).Times(0); + EXPECT_CALL(*mockDevice, getVersionString(_)).Times(0); + EXPECT_CALL(*mockDevice, getType(_)).Times(0); + EXPECT_CALL(*mockDevice, getSupportedExtensions(_)).Times(0); + EXPECT_CALL(*mockDevice, getNumberOfCacheFilesNeeded(_)).Times(0); +} + +void setupInitializationExpectationsV1_2(const sp& mockDevice) { + EXPECT_CALL(*mockDevice, getCapabilities(_)).Times(0); + EXPECT_CALL(*mockDevice, getCapabilities_1_1(_)).Times(0); + EXPECT_CALL(*mockDevice, getCapabilities_1_3(_)).Times(0); +} + +void setupInitializationExpectationsV1_3(const sp& mockDevice) { + EXPECT_CALL(*mockDevice, getCapabilities(_)).Times(0); + EXPECT_CALL(*mockDevice, getCapabilities_1_1(_)).Times(0); + EXPECT_CALL(*mockDevice, getCapabilities_1_2(_)).Times(0); +} + +void setupInitializationExpectations(const sp& mockDevice, Version version) { + switch (version) { + case Version::V1_0: + setupInitializationExpectationsV1_0(mockDevice); + return; + case Version::V1_1: + setupInitializationExpectationsV1_1(mockDevice); + return; + case Version::V1_2: + setupInitializationExpectationsV1_2(mockDevice); + return; + case Version::V1_3: + setupInitializationExpectationsV1_3(mockDevice); + return; + case Version::MOCK: + setupInitializationExpectationsV1_3(mockDevice); + return; + } + LOG(FATAL) << "unrecognized version: " << static_cast(version); +} + +void setupSuccessfulInitializationExpectations(const sp& mockDevice, Version version) { + EXPECT_CALL(*mockDevice, linkToDeathRet()).Times(testing::AnyNumber()); + + const int numCallsForV1_0 = (version == Version::V1_0 ? 1 : 0); + EXPECT_CALL(*mockDevice, getCapabilities(_)).Times(numCallsForV1_0); + + const int numCallsForV1_1 = (version == Version::V1_1 ? 1 : 0); + EXPECT_CALL(*mockDevice, getCapabilities_1_1(_)).Times(numCallsForV1_1); + + const int numCallsForV1_2 = (version == Version::V1_2 ? 1 : 0); + EXPECT_CALL(*mockDevice, getCapabilities_1_2(_)).Times(numCallsForV1_2); + + const int numCallsForAtLeastV1_3 = (version >= Version::V1_3 ? 1 : 0); + EXPECT_CALL(*mockDevice, getCapabilities_1_3(_)).Times(numCallsForAtLeastV1_3); + + const int numCallsForAtLeastV1_2 = (version >= Version::V1_2 ? 1 : 0); + EXPECT_CALL(*mockDevice, getVersionString(_)).Times(numCallsForAtLeastV1_2); + EXPECT_CALL(*mockDevice, getType(_)).Times(numCallsForAtLeastV1_2); + EXPECT_CALL(*mockDevice, getSupportedExtensions(_)).Times(numCallsForAtLeastV1_2); + EXPECT_CALL(*mockDevice, getNumberOfCacheFilesNeeded(_)).Times(numCallsForAtLeastV1_2); +} + +std::shared_ptr makeVersionedIDeviceFrom(const sp& mockDevice, + MockDeviceFactory* mockDeviceFactory, + Version version) { + setupInitializationExpectations(mockDevice, version); + const auto device = adaptAs(mockDevice, version); + ON_CALL(*mockDeviceFactory, Call(_)).WillByDefault(testing::Return(device)); + EXPECT_CALL(*mockDeviceFactory, Call(/*blocking=*/true)).Times(testing::AtLeast(1)); + const DeviceFactory makeDevice = mockDeviceFactory->AsStdFunction(); + return VersionedIDevice::create("MockDevice", makeDevice); +} + +std::shared_ptr makeVersionedIDeviceSuccessfulInitializationFrom( + const sp& device, MockDeviceFactory* mockDeviceFactory, Version version) { + setupSuccessfulInitializationExpectations(device, version); + return makeVersionedIDeviceFrom(device, mockDeviceFactory, version); +} + +std::function makeTransportFailure(status_t status) { + return [status] { return hardware::Status::fromStatusT(status); }; +} + +const auto makeGeneralTransportFailure = makeTransportFailure(NO_MEMORY); +const auto makeDeadObjectFailure = makeTransportFailure(DEAD_OBJECT); + +class VersionedIDeviceTest : public testing::Test { + protected: + const sp kMockDevice = MockDevice::create(); + const std::unique_ptr kMockMakeDevice = + std::make_unique(); +}; + +class VersionedIDeviceInitializationTest : public VersionedIDeviceTest {}; + +template +class VersionedIDeviceInitializedTest : public VersionedIDeviceTest { + protected: + void SetUp() override { + VersionedIDeviceTest::SetUp(); + ASSERT_NE(nullptr, kDevice.get()); + } + + const std::shared_ptr kDevice = + makeVersionedIDeviceSuccessfulInitializationFrom(kMockDevice, kMockMakeDevice.get(), + version); +}; + +class VersionedIDeviceV1_0Test : public VersionedIDeviceInitializedTest {}; +class VersionedIDeviceV1_1Test : public VersionedIDeviceInitializedTest {}; +class VersionedIDeviceV1_2Test : public VersionedIDeviceInitializedTest {}; +class VersionedIDeviceV1_3Test : public VersionedIDeviceInitializedTest {}; +class VersionedIDeviceMockTest : public VersionedIDeviceInitializedTest {}; + +// Simulate initialization/link error + +TEST_F(VersionedIDeviceInitializationTest, creationFailure) { + // setup failure + EXPECT_CALL(*kMockMakeDevice, Call(_)).Times(1).WillOnce(testing::Return(nullptr)); + const DeviceFactory makeDevice = kMockMakeDevice->AsStdFunction(); + + // run test + const auto device = VersionedIDevice::create("MockDevice", makeDevice); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, linkToDeathTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, linkToDeathRet()) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + EXPECT_CALL(*kMockMakeDevice, Call(_)).Times(1).WillOnce(testing::Return(kMockDevice)); + const DeviceFactory makeDevice = kMockMakeDevice->AsStdFunction(); + + // run test + const auto device = VersionedIDevice::create("MockDevice", makeDevice); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, linkToDeathReturnError) { + // setup failure + const auto ret = []() -> Return { return false; }; + EXPECT_CALL(*kMockMakeDevice, Call(_)).Times(1).WillOnce(testing::Return(kMockDevice)); + EXPECT_CALL(*kMockDevice, linkToDeathRet()).Times(1).WillOnce(InvokeWithoutArgs(ret)); + const DeviceFactory makeDevice = kMockMakeDevice->AsStdFunction(); + + // run test + const auto device = VersionedIDevice::create("MockDevice", makeDevice); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getCapabilitiesFailure) { + // setup failure + const auto ret = makeCallbackReturn(V1_0::ErrorStatus::GENERAL_FAILURE, V1_0::Capabilities{}); + EXPECT_CALL(*kMockDevice, getCapabilities(_)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_0); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getCapabilities_1_1Failure) { + // setup failure + const auto ret = makeCallbackReturn(V1_0::ErrorStatus::GENERAL_FAILURE, V1_1::Capabilities{}); + EXPECT_CALL(*kMockDevice, getCapabilities_1_1(_)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_1); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getCapabilities_1_2Failure) { + // setup failure + const auto ret = makeCallbackReturn(V1_0::ErrorStatus::GENERAL_FAILURE, V1_2::Capabilities{}); + EXPECT_CALL(*kMockDevice, getCapabilities_1_2(_)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_2); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getCapabilities_1_3Failure) { + // setup failure + const auto ret = makeCallbackReturn(V1_3::ErrorStatus::GENERAL_FAILURE, V1_3::Capabilities{}); + EXPECT_CALL(*kMockDevice, getCapabilities_1_3(_)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_3); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getVersionStringFailure) { + // setup failure + const auto ret = makeCallbackReturn(V1_0::ErrorStatus::GENERAL_FAILURE, ""); + EXPECT_CALL(*kMockDevice, getVersionString(_)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_2); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getTypeFailure) { + // setup failure + const auto ret = makeCallbackReturn(V1_0::ErrorStatus::GENERAL_FAILURE, DeviceType::OTHER); + EXPECT_CALL(*kMockDevice, getType(_)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_2); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getSupportedExtensionsFailure) { + // setup failure + const auto ret = makeCallbackReturn(V1_0::ErrorStatus::GENERAL_FAILURE, hidl_vec{}); + EXPECT_CALL(*kMockDevice, getSupportedExtensions(_)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_2); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getNumberOfCacheFilesNeededFailure) { + // setup failure + const auto ret = makeCallbackReturn(V1_0::ErrorStatus::GENERAL_FAILURE, kMaxNumberOfCacheFiles, + kMaxNumberOfCacheFiles); + EXPECT_CALL(*kMockDevice, getNumberOfCacheFilesNeeded(_)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_2); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, dataCacheFilesExceedsSpecifiedMax) { + // setup failure + const auto ret = makeCallbackReturn(V1_0::ErrorStatus::NONE, kMaxNumberOfCacheFiles + 1, + kMaxNumberOfCacheFiles); + EXPECT_CALL(*kMockDevice, getNumberOfCacheFilesNeeded(_)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_2); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, modelCacheFilesExceedsSpecifiedMax) { + // setup failure + const auto ret = makeCallbackReturn(V1_0::ErrorStatus::NONE, kMaxNumberOfCacheFiles, + kMaxNumberOfCacheFiles + 1); + EXPECT_CALL(*kMockDevice, getNumberOfCacheFilesNeeded(_)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_2); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getCapabilitiesTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, getCapabilities(_)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_0); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getCapabilities_1_1TransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, getCapabilities_1_1(_)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_1); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getCapabilities_1_2TransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, getCapabilities_1_2(_)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_2); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getCapabilities_1_3TransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, getCapabilities_1_3(_)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_3); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getVersionStringTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, getVersionString(_)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_2); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getTypeTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, getType(_)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_2); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getSupportedExtensionsTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, getSupportedExtensions(_)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_2); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +TEST_F(VersionedIDeviceInitializationTest, getNumberOfCacheFilesNeededTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, getNumberOfCacheFilesNeeded(_)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto device = makeVersionedIDeviceFrom(kMockDevice, kMockMakeDevice.get(), Version::V1_2); + + // verify failure + EXPECT_EQ(nullptr, device.get()); +} + +// Ensure device has cached metadata + +TEST_F(VersionedIDeviceV1_0Test, getCapabilities) { + // run test + const auto capabilities = kDevice->getCapabilities(); + const auto cached = kDevice->getCapabilities(); + + // verify success + EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceScalar); + EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceTensor); + EXPECT_LT(0u, capabilities.operandPerformance.size()); + EXPECT_EQ(cached, capabilities); +} + +TEST_F(VersionedIDeviceV1_1Test, getCapabilities) { + // run test + const auto capabilities = kDevice->getCapabilities(); + const auto cached = kDevice->getCapabilities(); + + // verify success + EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceScalar); + EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceTensor); + EXPECT_LT(0u, capabilities.operandPerformance.size()); + EXPECT_EQ(cached, capabilities); +} + +TEST_F(VersionedIDeviceV1_2Test, getCapabilities) { + // run test + const auto capabilities = kDevice->getCapabilities(); + const auto cached = kDevice->getCapabilities(); + + // verify success + EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceScalar); + EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceTensor); + EXPECT_EQ(0u, capabilities.operandPerformance.size()); + EXPECT_EQ(cached, capabilities); +} + +TEST_F(VersionedIDeviceV1_3Test, getCapabilities) { + // run test + const auto capabilities = kDevice->getCapabilities(); + const auto cached = kDevice->getCapabilities(); + + // verify success + EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceScalar); + EXPECT_EQ(PerformanceInfo{}, capabilities.relaxedFloat32toFloat16PerformanceTensor); + EXPECT_EQ(0u, capabilities.operandPerformance.size()); + EXPECT_EQ(cached, capabilities); +} + +TEST_F(VersionedIDeviceV1_0Test, getVersionString) { + // run test + const auto versionString = kDevice->getVersionString(); + const auto cached = kDevice->getVersionString(); + + // verify success + EXPECT_EQ("UNKNOWN", versionString); + EXPECT_EQ(cached, versionString); +} + +TEST_F(VersionedIDeviceV1_1Test, getVersionString) { + // run test + const auto versionString = kDevice->getVersionString(); + const auto cached = kDevice->getVersionString(); + + // verify success + EXPECT_EQ("UNKNOWN", versionString); + EXPECT_EQ(cached, versionString); +} + +TEST_F(VersionedIDeviceV1_2Test, getVersionString) { + // run test + const auto versionString = kDevice->getVersionString(); + const auto cached = kDevice->getVersionString(); + + // verify success + EXPECT_EQ("Google-MockV1", versionString); + EXPECT_EQ(cached, versionString); +} + +TEST_F(VersionedIDeviceV1_3Test, getVersionString) { + // run test + const auto versionString = kDevice->getVersionString(); + const auto cached = kDevice->getVersionString(); + + // verify success + EXPECT_EQ("Google-MockV1", versionString); + EXPECT_EQ(cached, versionString); +} + +TEST_F(VersionedIDeviceV1_0Test, getType) { + // run test + const auto type = kDevice->getType(); + const auto cached = kDevice->getType(); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_DEVICE_UNKNOWN, type); + EXPECT_EQ(cached, type); +} + +TEST_F(VersionedIDeviceV1_1Test, getType) { + // run test + const auto type = kDevice->getType(); + const auto cached = kDevice->getType(); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_DEVICE_UNKNOWN, type); + EXPECT_EQ(cached, type); +} + +TEST_F(VersionedIDeviceV1_2Test, getType) { + // run test + const auto type = kDevice->getType(); + const auto cached = kDevice->getType(); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_DEVICE_OTHER, type); + EXPECT_EQ(cached, type); +} + +TEST_F(VersionedIDeviceV1_3Test, getType) { + // run test + const auto type = kDevice->getType(); + const auto cached = kDevice->getType(); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_DEVICE_OTHER, type); + EXPECT_EQ(cached, type); +} + +TEST_F(VersionedIDeviceV1_0Test, getSupportedExtensions) { + // run test + const auto supportedExtensions = kDevice->getSupportedExtensions(); + const auto cached = kDevice->getSupportedExtensions(); + + // verify success + EXPECT_EQ(0u, supportedExtensions.size()); + EXPECT_EQ(cached, supportedExtensions); +} + +TEST_F(VersionedIDeviceV1_1Test, getSupportedExtensions) { + // run test + const auto supportedExtensions = kDevice->getSupportedExtensions(); + const auto cached = kDevice->getSupportedExtensions(); + + // verify success + EXPECT_EQ(0u, supportedExtensions.size()); + EXPECT_EQ(cached, supportedExtensions); +} + +TEST_F(VersionedIDeviceV1_2Test, getSupportedExtensions) { + // run test + const auto supportedExtensions = kDevice->getSupportedExtensions(); + const auto cached = kDevice->getSupportedExtensions(); + + // verify success + EXPECT_EQ(0u, supportedExtensions.size()); + EXPECT_EQ(cached, supportedExtensions); +} + +TEST_F(VersionedIDeviceV1_3Test, getSupportedExtensions) { + // run test + const auto supportedExtensions = kDevice->getSupportedExtensions(); + const auto cached = kDevice->getSupportedExtensions(); + + // verify success + EXPECT_EQ(0u, supportedExtensions.size()); + EXPECT_EQ(cached, supportedExtensions); +} + +TEST_F(VersionedIDeviceV1_0Test, getNumberOfCacheFilesNeeded) { + // run test + const auto [dataCacheFilesNeeded, modelCacheFilesNeeded] = + kDevice->getNumberOfCacheFilesNeeded(); + const auto [cachedDataCacheFilesNeeded, cachedModelCacheFilesNeeded] = + kDevice->getNumberOfCacheFilesNeeded(); + + // verify success + EXPECT_EQ(kNoCacheFilesNeeded, dataCacheFilesNeeded); + EXPECT_EQ(kNoCacheFilesNeeded, modelCacheFilesNeeded); + EXPECT_EQ(cachedDataCacheFilesNeeded, dataCacheFilesNeeded); + EXPECT_EQ(cachedModelCacheFilesNeeded, modelCacheFilesNeeded); +} + +TEST_F(VersionedIDeviceV1_1Test, getNumberOfCacheFilesNeeded) { + // run test + const auto [dataCacheFilesNeeded, modelCacheFilesNeeded] = + kDevice->getNumberOfCacheFilesNeeded(); + const auto [cachedDataCacheFilesNeeded, cachedModelCacheFilesNeeded] = + kDevice->getNumberOfCacheFilesNeeded(); + + // verify success + EXPECT_EQ(kNoCacheFilesNeeded, dataCacheFilesNeeded); + EXPECT_EQ(kNoCacheFilesNeeded, modelCacheFilesNeeded); + EXPECT_EQ(cachedDataCacheFilesNeeded, dataCacheFilesNeeded); + EXPECT_EQ(cachedModelCacheFilesNeeded, modelCacheFilesNeeded); +} + +TEST_F(VersionedIDeviceV1_2Test, getNumberOfCacheFilesNeeded) { + // run test + const auto [dataCacheFilesNeeded, modelCacheFilesNeeded] = + kDevice->getNumberOfCacheFilesNeeded(); + const auto [cachedDataCacheFilesNeeded, cachedModelCacheFilesNeeded] = + kDevice->getNumberOfCacheFilesNeeded(); + + // verify success + EXPECT_EQ(kMaxNumberOfCacheFiles, dataCacheFilesNeeded); + EXPECT_EQ(kMaxNumberOfCacheFiles, modelCacheFilesNeeded); + EXPECT_EQ(cachedDataCacheFilesNeeded, dataCacheFilesNeeded); + EXPECT_EQ(cachedModelCacheFilesNeeded, modelCacheFilesNeeded); +} + +TEST_F(VersionedIDeviceV1_3Test, getNumberOfCacheFilesNeeded) { + // run test + const auto [dataCacheFilesNeeded, modelCacheFilesNeeded] = + kDevice->getNumberOfCacheFilesNeeded(); + const auto [cachedDataCacheFilesNeeded, cachedModelCacheFilesNeeded] = + kDevice->getNumberOfCacheFilesNeeded(); + + // verify success + EXPECT_EQ(kMaxNumberOfCacheFiles, dataCacheFilesNeeded); + EXPECT_EQ(kMaxNumberOfCacheFiles, modelCacheFilesNeeded); + EXPECT_EQ(cachedDataCacheFilesNeeded, dataCacheFilesNeeded); + EXPECT_EQ(cachedModelCacheFilesNeeded, modelCacheFilesNeeded); +} + +TEST_F(VersionedIDeviceV1_0Test, getFeatureLevel) { + // run test + const auto featureLevel = kDevice->getFeatureLevel(); + const auto cached = kDevice->getFeatureLevel(); + + // verify success + constexpr int64_t expectedFeatureLevel = __ANDROID_API_O_MR1__; + EXPECT_EQ(expectedFeatureLevel, featureLevel); + EXPECT_EQ(cached, featureLevel); +} + +TEST_F(VersionedIDeviceV1_1Test, getFeatureLevel) { + // run test + const auto featureLevel = kDevice->getFeatureLevel(); + const auto cached = kDevice->getFeatureLevel(); + + // verify success + constexpr int64_t expectedFeatureLevel = __ANDROID_API_P__; + EXPECT_EQ(expectedFeatureLevel, featureLevel); + EXPECT_EQ(cached, featureLevel); +} + +TEST_F(VersionedIDeviceV1_2Test, getFeatureLevel) { + // run test + const auto featureLevel = kDevice->getFeatureLevel(); + const auto cached = kDevice->getFeatureLevel(); + + // verify success + constexpr int64_t expectedFeatureLevel = __ANDROID_API_Q__; + EXPECT_EQ(expectedFeatureLevel, featureLevel); + EXPECT_EQ(cached, featureLevel); +} + +TEST_F(VersionedIDeviceV1_3Test, getFeatureLevel) { + // run test + const auto featureLevel = kDevice->getFeatureLevel(); + const auto cached = kDevice->getFeatureLevel(); + + // verify success + constexpr int64_t expectedFeatureLevel = __ANDROID_API_R__; + EXPECT_EQ(expectedFeatureLevel, featureLevel); + EXPECT_EQ(cached, featureLevel); +} + +// Simulate successful test + +TEST_F(VersionedIDeviceV1_0Test, getSupportedOperations) { + // setup call + const auto ret = [](const auto& /*model*/, const auto cb) { + cb(V1_0::ErrorStatus::NONE, {}); + return Void(); + }; + EXPECT_CALL(*kMockDevice, getSupportedOperations(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); + + // verify success + EXPECT_EQ(V1_3::ErrorStatus::NONE, resultCode); + EXPECT_EQ(0u, supportedOperations.size()); +} + +TEST_F(VersionedIDeviceV1_1Test, getSupportedOperations) { + // setup call + const auto ret = [](const auto& /*model*/, const auto cb) { + cb(V1_0::ErrorStatus::NONE, {}); + return Void(); + }; + EXPECT_CALL(*kMockDevice, getSupportedOperations_1_1(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); + + // verify success + EXPECT_EQ(V1_3::ErrorStatus::NONE, resultCode); + EXPECT_EQ(0u, supportedOperations.size()); +} + +TEST_F(VersionedIDeviceV1_2Test, getSupportedOperations) { + // setup call + const auto ret = [](const auto& /*model*/, const auto cb) { + cb(V1_0::ErrorStatus::NONE, {}); + return Void(); + }; + EXPECT_CALL(*kMockDevice, getSupportedOperations_1_2(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); + + // verify success + EXPECT_EQ(V1_3::ErrorStatus::NONE, resultCode); + EXPECT_EQ(0u, supportedOperations.size()); +} + +TEST_F(VersionedIDeviceV1_3Test, getSupportedOperations) { + // setup call + const auto ret = [](const auto& /*model*/, const auto cb) { + cb(V1_3::ErrorStatus::NONE, {}); + return Void(); + }; + EXPECT_CALL(*kMockDevice, getSupportedOperations_1_3(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); + + // verify success + EXPECT_EQ(V1_3::ErrorStatus::NONE, resultCode); + EXPECT_EQ(0u, supportedOperations.size()); +} + +TEST_F(VersionedIDeviceV1_0Test, prepareModel) { + // setup call + const sp mockPreparedModel = MockPreparedModel::create(); + const auto ret = makePreparedModelReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, + mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_NE(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_1Test, prepareModel) { + // setup call + const sp mockPreparedModel = MockPreparedModel::create(); + const auto ret = makePreparedModel_1_1Return(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, + mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_1(_, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_NE(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_2Test, prepareModel) { + // setup call + const sp mockPreparedModel = MockPreparedModel::create(); + const auto ret = makePreparedModel_1_2Return(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, + mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_2(_, _, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_NE(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_3Test, prepareModel) { + // setup call + const sp mockPreparedModel = MockPreparedModel::create(); + const auto ret = makePreparedModel_1_3Return(V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::NONE, + mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_NE(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_0Test, allocate) { + // run test + const auto [status, buffer, token] = kDevice->allocate({}, {}, {}, {}); + + // verify success + EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, status); + EXPECT_EQ(nullptr, buffer.get()); + EXPECT_EQ(0u, token); +} + +TEST_F(VersionedIDeviceV1_1Test, allocate) { + // run test + const auto [status, buffer, token] = kDevice->allocate({}, {}, {}, {}); + + // verify success + EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, status); + EXPECT_EQ(nullptr, buffer.get()); + EXPECT_EQ(0u, token); +} + +TEST_F(VersionedIDeviceV1_2Test, allocate) { + // run test + const auto [status, buffer, token] = kDevice->allocate({}, {}, {}, {}); + + // verify success + EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, status); + EXPECT_EQ(nullptr, buffer.get()); + EXPECT_EQ(0u, token); +} + +TEST_F(VersionedIDeviceV1_3Test, allocate) { + // setup call + const sp mockBuffer = new MockBuffer(); + constexpr uint32_t mockToken = 1; + const auto ret = [mockBuffer](const BufferDesc& /*desc*/, + const hidl_vec>& /*preparedModels*/, + const hidl_vec& /*inputRoles*/, + const hidl_vec& /*outputRoles*/, + V1_3::IDevice::allocate_cb cb) -> Return { + cb(V1_3::ErrorStatus::NONE, mockBuffer, mockToken); + return Void(); + }; + EXPECT_CALL(*kMockDevice, allocate(_, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [status, buffer, token] = kDevice->allocate({}, {}, {}, {}); + + // verify success + EXPECT_EQ(V1_3::ErrorStatus::NONE, status); + EXPECT_NE(nullptr, buffer.get()); + EXPECT_NE(0u, token); +} + +TEST_F(VersionedIDeviceMockTest, wait) { + // setup call + const auto ret = []() -> Return { return {}; }; + EXPECT_CALL(*kMockDevice, ping()).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto resultCode = kDevice->wait(); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); +} + +// Simulate general failure + +TEST_F(VersionedIDeviceV1_0Test, getSupportedOperationsFailure) { + // setup failure + const auto ret = [](const auto& /*model*/, const auto cb) { + cb(V1_0::ErrorStatus::GENERAL_FAILURE, {}); + return Void(); + }; + EXPECT_CALL(*kMockDevice, getSupportedOperations(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); + + // verify failure + EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(0u, supportedOperations.size()); +} + +TEST_F(VersionedIDeviceV1_1Test, getSupportedOperationsFailure) { + // setup failure + const auto ret = [](const auto& /*model*/, const auto cb) { + cb(V1_0::ErrorStatus::GENERAL_FAILURE, {}); + return Void(); + }; + EXPECT_CALL(*kMockDevice, getSupportedOperations_1_1(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); + + // verify failure + EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(0u, supportedOperations.size()); +} + +TEST_F(VersionedIDeviceV1_2Test, getSupportedOperationsFailure) { + // setup failure + const auto ret = [](const auto& /*model*/, const auto cb) { + cb(V1_0::ErrorStatus::GENERAL_FAILURE, {}); + return Void(); + }; + EXPECT_CALL(*kMockDevice, getSupportedOperations_1_2(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); + + // verify failure + EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(0u, supportedOperations.size()); +} + +TEST_F(VersionedIDeviceV1_3Test, getSupportedOperationsFailure) { + // setup failure + const auto ret = [](const auto& /*model*/, const auto cb) { + cb(V1_3::ErrorStatus::GENERAL_FAILURE, {}); + return Void(); + }; + EXPECT_CALL(*kMockDevice, getSupportedOperations_1_3(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); + + // verify failure + EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(0u, supportedOperations.size()); +} + +TEST_F(VersionedIDeviceV1_0Test, prepareModelLaunchFailure) { + // setup failure + const sp mockPreparedModel = MockPreparedModel::create(); + const auto ret = makePreparedModelReturn(V1_0::ErrorStatus::GENERAL_FAILURE, + V1_0::ErrorStatus::NONE, mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_1Test, prepareModelLaunchFailure) { + // setup failure + const sp mockPreparedModel = MockPreparedModel::create(); + const auto ret = makePreparedModel_1_1Return(V1_0::ErrorStatus::GENERAL_FAILURE, + V1_0::ErrorStatus::NONE, mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_1(_, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_2Test, prepareModelLaunchFailure) { + // setup failure + const sp mockPreparedModel = MockPreparedModel::create(); + const auto ret = makePreparedModel_1_2Return(V1_0::ErrorStatus::GENERAL_FAILURE, + V1_0::ErrorStatus::NONE, mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_2(_, _, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_3Test, prepareModelLaunchFailure) { + // setup failure + const sp mockPreparedModel = MockPreparedModel::create(); + const auto ret = makePreparedModel_1_3Return(V1_3::ErrorStatus::GENERAL_FAILURE, + V1_3::ErrorStatus::NONE, mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_0Test, prepareModelReturnFailure) { + // setup failure + const sp mockPreparedModel = MockPreparedModel::create(); + const auto ret = makePreparedModelReturn(V1_0::ErrorStatus::NONE, + V1_0::ErrorStatus::GENERAL_FAILURE, mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_1Test, prepareModelReturnFailure) { + // setup failure + const sp mockPreparedModel = MockPreparedModel::create(); + const auto ret = makePreparedModel_1_1Return( + V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE, mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_1(_, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_2Test, prepareModelReturnFailure) { + // setup failure + const sp mockPreparedModel = MockPreparedModel::create(); + const auto ret = makePreparedModel_1_2Return( + V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE, mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_2(_, _, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_3Test, prepareModelReturnFailure) { + // setup failure + const sp mockPreparedModel = MockPreparedModel::create(); + const auto ret = makePreparedModel_1_3Return( + V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::GENERAL_FAILURE, mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_0Test, prepareModelNullptrError) { + // setup failure + const sp mockPreparedModel = nullptr; + const auto ret = makePreparedModelReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, + mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_1Test, prepareModelNullptrError) { + // setup failure + const sp mockPreparedModel = nullptr; + const auto ret = makePreparedModel_1_1Return(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, + mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_1(_, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_2Test, prepareModelNullptrError) { + // setup failure + const sp mockPreparedModel = nullptr; + const auto ret = makePreparedModel_1_2Return(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, + mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_2(_, _, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_3Test, prepareModelNullptrError) { + // setup failure + const sp mockPreparedModel = nullptr; + const auto ret = makePreparedModel_1_3Return(V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::NONE, + mockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_3Test, allocateFailure) { + // setup failure + const auto ret = [](const BufferDesc& /*desc*/, + const hidl_vec>& /*preparedModels*/, + const hidl_vec& /*inputRoles*/, + const hidl_vec& /*outputRoles*/, + V1_3::IDevice::allocate_cb cb) -> Return { + cb(V1_3::ErrorStatus::GENERAL_FAILURE, nullptr, 0); + return Void(); + }; + EXPECT_CALL(*kMockDevice, allocate(_, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [status, buffer, token] = kDevice->allocate({}, {}, {}, {}); + + // verify failure + EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, status); + EXPECT_EQ(nullptr, buffer.get()); + EXPECT_EQ(0u, token); +} + +// Simulate transport failure + +TEST_F(VersionedIDeviceV1_0Test, getSupportedOperationsTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, getSupportedOperations(_, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); + + // verify failure + EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(0u, supportedOperations.size()); +} + +TEST_F(VersionedIDeviceV1_1Test, getSupportedOperationsTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, getSupportedOperations_1_1(_, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); + + // verify failure + EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(0u, supportedOperations.size()); +} + +TEST_F(VersionedIDeviceV1_2Test, getSupportedOperationsTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, getSupportedOperations_1_2(_, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); + + // verify failure + EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(0u, supportedOperations.size()); +} + +TEST_F(VersionedIDeviceV1_3Test, getSupportedOperationsTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, getSupportedOperations_1_3(_, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto metaModel = MetaModel({}, /*strictSlicing=*/true); + const auto [resultCode, supportedOperations] = kDevice->getSupportedOperations(metaModel); + + // verify failure + EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, resultCode); + EXPECT_EQ(0u, supportedOperations.size()); +} + +TEST_F(VersionedIDeviceV1_0Test, prepareModelTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, prepareModel(_, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_1Test, prepareModelTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, prepareModel_1_1(_, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_2Test, prepareModelTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, prepareModel_1_2(_, _, _, _, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_3Test, prepareModelTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceV1_3Test, allocateTransportFailure) { + // setup failure + EXPECT_CALL(*kMockDevice, allocate(_, _, _, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto [status, buffer, token] = kDevice->allocate({}, {}, {}, {}); + + // verify failure + EXPECT_EQ(V1_3::ErrorStatus::GENERAL_FAILURE, status); + EXPECT_EQ(nullptr, buffer.get()); + EXPECT_EQ(0u, token); +} + +TEST_F(VersionedIDeviceMockTest, waitTransportFailure) { + // setup call + EXPECT_CALL(*kMockDevice, ping()) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto resultCode = kDevice->wait(); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); +} + +// Simulate service crash + +// TODO: enable this test once b/154183300 is fixed. +TEST_F(VersionedIDeviceMockTest, DISABLED_prepareModelRecoverCrash) { + // setup original device calls + EXPECT_CALL(*kMockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); + EXPECT_CALL(*kMockDevice, ping()).Times(1).WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); + + // setup recovery call + const sp mockRecoveredDevice = MockDevice::create(); + EXPECT_CALL(*kMockMakeDevice, Call(/*blocking=*/false)) + .Times(1) + .WillOnce(testing::Return(mockRecoveredDevice)); + + // setup recovered device calls + const sp mockPreparedModel = MockPreparedModel::create(); + const auto ret = makePreparedModel_1_3Return(V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::NONE, + mockPreparedModel); + EXPECT_CALL(*mockRecoveredDevice, linkToDeathRet()).Times(1); + EXPECT_CALL(*mockRecoveredDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_NE(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceMockTest, prepareModelFullCrash) { + // setup failure + EXPECT_CALL(*kMockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)) + .Times(1) + .WillRepeatedly(InvokeWithoutArgs(makeDeadObjectFailure)); + EXPECT_CALL(*kMockDevice, ping()) + .Times(1) + .WillRepeatedly(InvokeWithoutArgs(makeDeadObjectFailure)); + EXPECT_CALL(*kMockMakeDevice, Call(/*blocking=*/false)) + .Times(1) + .WillOnce(testing::Return(nullptr)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_DEAD_OBJECT, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceMockTest, prepareModelAsyncCrash) { + // setup failure + const auto ret = [this]() -> Return { + kMockDevice->simulateCrash(); + return V1_3::ErrorStatus::NONE; + }; + EXPECT_CALL(*kMockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_DEAD_OBJECT, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIDeviceMockTest, waitCrash) { + // setup failure + EXPECT_CALL(*kMockDevice, ping()) + .Times(1) + .WillRepeatedly(InvokeWithoutArgs(makeDeadObjectFailure)); + EXPECT_CALL(*kMockMakeDevice, Call(/*blocking=*/true)) + .Times(1) + .WillOnce(testing::Return(nullptr)); + + // run test + const auto resultCode = kDevice->wait(); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); +} + +TEST_F(VersionedIDeviceMockTest, waitRecoverCrash) { + // setup original device calls + EXPECT_CALL(*kMockDevice, ping()).Times(1).WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); + + // setup recovery call + const sp mockRecoveredDevice = MockDevice::create(); + EXPECT_CALL(*kMockMakeDevice, Call(/*blocking=*/true)) + .Times(1) + .WillOnce(testing::Return(mockRecoveredDevice)); + + // setup recovered device calls + const auto ret = []() -> Return { return true; }; + EXPECT_CALL(*mockRecoveredDevice, linkToDeathRet()).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto resultCode = kDevice->wait(); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); +} + +TEST_F(VersionedIDeviceMockTest, waitFailedRecoverCrash) { + // setup original device calls + EXPECT_CALL(*kMockDevice, ping()).Times(1).WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); + + // setup recovery call + const sp mockRecoveredDevice = MockDevice::create(); + EXPECT_CALL(*kMockMakeDevice, Call(/*blocking=*/true)) + .Times(1) + .WillOnce(testing::Return(mockRecoveredDevice)); + + // setup recovered device calls + EXPECT_CALL(*mockRecoveredDevice, linkToDeathRet()) + .Times(1) + .WillOnce(makeGeneralTransportFailure); + + // run test + const auto resultCode = kDevice->wait(); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); +} + +// Harness for VersionedIPreparedModel failures. + +class VersionedIPreparedModelInitializationTest : public VersionedIDeviceMockTest { + protected: + const sp kMockPreparedModel = MockPreparedModel::create(); +}; + +std::shared_ptr makeVersionedIPreparedModelSuccessfulInitializationFrom( + const sp& mockDevice, const sp& mockPreparedModel, + const VersionedIDevice& device) { + const auto retV1_0 = makePreparedModelReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, + mockPreparedModel); + const auto retV1_1 = makePreparedModel_1_1Return(V1_0::ErrorStatus::NONE, + V1_0::ErrorStatus::NONE, mockPreparedModel); + const auto retV1_2 = makePreparedModel_1_2Return(V1_0::ErrorStatus::NONE, + V1_0::ErrorStatus::NONE, mockPreparedModel); + const auto retV1_3 = makePreparedModel_1_3Return(V1_3::ErrorStatus::NONE, + V1_3::ErrorStatus::NONE, mockPreparedModel); + + ON_CALL(*mockDevice, prepareModel(_, _)).WillByDefault(Invoke(retV1_0)); + ON_CALL(*mockDevice, prepareModel_1_1(_, _, _)).WillByDefault(Invoke(retV1_1)); + ON_CALL(*mockDevice, prepareModel_1_2(_, _, _, _, _, _)).WillByDefault(Invoke(retV1_2)); + ON_CALL(*mockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)).WillByDefault(Invoke(retV1_3)); + + EXPECT_CALL(*mockDevice, prepareModel(_, _)).Times(testing::AnyNumber()); + EXPECT_CALL(*mockDevice, prepareModel_1_1(_, _, _)).Times(testing::AnyNumber()); + EXPECT_CALL(*mockDevice, prepareModel_1_2(_, _, _, _, _, _)).Times(testing::AnyNumber()); + EXPECT_CALL(*mockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)).Times(testing::AnyNumber()); + + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = device.prepareModel(makeModel, {}, {}, {}, {}, {}); + + CHECK_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + CHECK(preparedModel != nullptr); + + return preparedModel; +} + +template +class VersionedIPreparedModelTest : public VersionedIDeviceInitializedTest { + using Base = VersionedIDeviceInitializedTest; + + protected: + void SetUp() override { + VersionedIDeviceInitializedTest::SetUp(); + ASSERT_NE(nullptr, kPreparedModel.get()); + } + + const sp kMockPreparedModel = MockPreparedModel::create(); + const std::shared_ptr kPreparedModel = + makeVersionedIPreparedModelSuccessfulInitializationFrom( + Base::kMockDevice, kMockPreparedModel, *Base::kDevice); +}; + +class VersionedIPreparedModelV1_0Test : public VersionedIPreparedModelTest {}; +class VersionedIPreparedModelV1_1Test : public VersionedIPreparedModelTest {}; +class VersionedIPreparedModelV1_2Test : public VersionedIPreparedModelTest {}; +class VersionedIPreparedModelV1_3Test : public VersionedIPreparedModelTest {}; +class VersionedIPreparedModelMockTest : public VersionedIPreparedModelTest {}; + +// Simulate initialization/link error + +TEST_F(VersionedIPreparedModelInitializationTest, linkToDeathTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, linkToDeathRet()) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + const auto ret = makePreparedModel_1_3Return(V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::NONE, + kMockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIPreparedModelInitializationTest, linkToDeathDeadObject) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, linkToDeathRet()) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); + const auto ret = makePreparedModel_1_3Return(V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::NONE, + kMockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_DEAD_OBJECT, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +TEST_F(VersionedIPreparedModelInitializationTest, linkToDeathReturnError) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, linkToDeathRet()) + .Times(1) + .WillOnce(InvokeWithoutArgs([]() -> Return { return false; })); + const auto ret = makePreparedModel_1_3Return(V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::NONE, + kMockPreparedModel); + EXPECT_CALL(*kMockDevice, prepareModel_1_3(_, _, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const ModelFactory makeModel = [] { return V1_3::Model{}; }; + const auto [resultCode, preparedModel] = kDevice->prepareModel(makeModel, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +// Simulate successful test + +TEST_F(VersionedIPreparedModelV1_0Test, executeAsync) { + // setup call + const auto ret = makeExecuteReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE); + EXPECT_CALL(*kMockPreparedModel, execute(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_1Test, executeAsync) { + // setup call + const auto ret = makeExecuteReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE); + EXPECT_CALL(*kMockPreparedModel, execute(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_2Test, executeAsync) { + // setup call + const auto ret = + makeExecute_1_2Return(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, {}, kNoTiming); + EXPECT_CALL(*kMockPreparedModel, execute_1_2(_, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_3Test, executeAsync) { + // setup call + const auto ret = + makeExecute_1_3Return(V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::NONE, {}, kNoTiming); + EXPECT_CALL(*kMockPreparedModel, execute_1_3(_, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_0Test, executePreferSync) { + // setup call + const auto ret = makeExecuteReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE); + EXPECT_CALL(*kMockPreparedModel, execute(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/true); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_1Test, executePreferSync) { + // setup call + const auto ret = makeExecuteReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE); + EXPECT_CALL(*kMockPreparedModel, execute(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/true); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_2Test, executePreferSync) { + // setup call + const auto ret = makeExecuteSynchronouslyReturn(V1_0::ErrorStatus::NONE, {}, kNoTiming); + EXPECT_CALL(*kMockPreparedModel, executeSynchronously(_, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/true); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_3Test, executePreferSync) { + // setup call + const auto ret = makeExecuteSynchronously_1_3Return(V1_3::ErrorStatus::NONE, {}, kNoTiming); + EXPECT_CALL(*kMockPreparedModel, executeSynchronously_1_3(_, _, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/true); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_0Test, executeFenced) { + // setup call + const auto ret = makeExecuteReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE); + EXPECT_CALL(*kMockPreparedModel, execute(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, syncFence, dispatchCallback, timing] = + kPreparedModel->executeFenced({}, {}, {}, {}, {}, {}); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, dispatchCallback.get()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_1Test, executeFenced) { + // setup call + const auto ret = makeExecuteReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE); + EXPECT_CALL(*kMockPreparedModel, execute(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, syncFence, dispatchCallback, timing] = + kPreparedModel->executeFenced({}, {}, {}, {}, {}, {}); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, dispatchCallback.get()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_2Test, executeFenced) { + // setup call + const auto ret = makeExecuteSynchronouslyReturn(V1_0::ErrorStatus::NONE, {}, kNoTiming); + EXPECT_CALL(*kMockPreparedModel, executeSynchronously(_, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, syncFence, dispatchCallback, timing] = + kPreparedModel->executeFenced({}, {}, {}, {}, {}, {}); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, dispatchCallback.get()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_3Test, executeFenced) { + // setup call + auto memory = allocateSharedMemory(4); + hidl_handle fakeSyncFence(memory.handle()); + const sp callback = new MockFencedExecutionCallback(); + const auto ret = makeExecuteFencedReturn(V1_3::ErrorStatus::NONE, fakeSyncFence, callback); + EXPECT_CALL(*kMockPreparedModel, executeFenced(_, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, syncFence, dispatchCallback, timing] = + kPreparedModel->executeFenced({}, {}, {}, {}, {}, {}); + + // verify success + EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode); + EXPECT_NE(nullptr, syncFence.getNativeHandle()); + EXPECT_NE(nullptr, dispatchCallback.get()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_0Test, configureExecutionBurst) { + // run test + const auto executionBurstController = + kPreparedModel->configureExecutionBurst(/*preferPowerOverLatency=*/false); + + // verify success + EXPECT_EQ(nullptr, executionBurstController); +} + +TEST_F(VersionedIPreparedModelV1_1Test, configureExecutionBurst) { + // run test + const auto executionBurstController = + kPreparedModel->configureExecutionBurst(/*preferPowerOverLatency=*/false); + + // verify success + EXPECT_EQ(nullptr, executionBurstController); +} + +TEST_F(VersionedIPreparedModelV1_2Test, configureExecutionBurst) { + // setup call + const sp burstContext = new MockBurstContext(); + const auto ret = makeConfigureExecutionBurst(V1_0::ErrorStatus::NONE, burstContext); + EXPECT_CALL(*kMockPreparedModel, configureExecutionBurst(_, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const auto executionBurstController = + kPreparedModel->configureExecutionBurst(/*preferPowerOverLatency=*/false); + + // verify success + EXPECT_NE(nullptr, executionBurstController); +} + +TEST_F(VersionedIPreparedModelV1_3Test, configureExecutionBurst) { + // setup call + const sp burstContext = new MockBurstContext(); + const auto ret = makeConfigureExecutionBurst(V1_0::ErrorStatus::NONE, burstContext); + EXPECT_CALL(*kMockPreparedModel, configureExecutionBurst(_, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const auto executionBurstController = + kPreparedModel->configureExecutionBurst(/*preferPowerOverLatency=*/false); + + // verify success + EXPECT_NE(nullptr, executionBurstController); +} + +// Simulate general failure + +TEST_F(VersionedIPreparedModelV1_0Test, executeAsyncLaunchFailure) { + // setup failure + const auto ret = makeExecuteReturn(V1_0::ErrorStatus::GENERAL_FAILURE, V1_0::ErrorStatus::NONE); + EXPECT_CALL(*kMockPreparedModel, execute(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_1Test, executeAsyncLaunchFailure) { + // setup failure + const auto ret = makeExecuteReturn(V1_0::ErrorStatus::GENERAL_FAILURE, V1_0::ErrorStatus::NONE); + EXPECT_CALL(*kMockPreparedModel, execute(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_2Test, executeAsyncLaunchFailure) { + // setup failure + const auto ret = makeExecute_1_2Return(V1_0::ErrorStatus::GENERAL_FAILURE, + V1_0::ErrorStatus::NONE, {}, kNoTiming); + EXPECT_CALL(*kMockPreparedModel, execute_1_2(_, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_3Test, executeAsyncLaunchFailure) { + // setup failure + const auto ret = makeExecute_1_3Return(V1_3::ErrorStatus::GENERAL_FAILURE, + V1_3::ErrorStatus::NONE, {}, kNoTiming); + EXPECT_CALL(*kMockPreparedModel, execute_1_3(_, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_0Test, executeAsyncReturnFailure) { + // setup failure + const auto ret = makeExecuteReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE); + EXPECT_CALL(*kMockPreparedModel, execute(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_1Test, executeAsyncReturnFailure) { + // setup failure + const auto ret = makeExecuteReturn(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE); + EXPECT_CALL(*kMockPreparedModel, execute(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_2Test, executeAsyncReturnFailure) { + // setup failure + const auto ret = makeExecute_1_2Return(V1_0::ErrorStatus::NONE, + V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + EXPECT_CALL(*kMockPreparedModel, execute_1_2(_, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_3Test, executeAsyncReturnFailure) { + // setup failure + const auto ret = makeExecute_1_3Return(V1_3::ErrorStatus::NONE, + V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + EXPECT_CALL(*kMockPreparedModel, execute_1_3(_, _, _, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_0Test, executePreferSyncFailure) { + // setup failure + const auto ret = makeExecuteReturn(V1_0::ErrorStatus::GENERAL_FAILURE, + V1_0::ErrorStatus::GENERAL_FAILURE); + EXPECT_CALL(*kMockPreparedModel, execute(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/true); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_1Test, executePreferSyncFailure) { + // setup failure + const auto ret = makeExecuteReturn(V1_0::ErrorStatus::GENERAL_FAILURE, + V1_0::ErrorStatus::GENERAL_FAILURE); + EXPECT_CALL(*kMockPreparedModel, execute(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/true); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_2Test, executePreferSyncFailure) { + // setup failure + const auto ret = + makeExecuteSynchronouslyReturn(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + EXPECT_CALL(*kMockPreparedModel, executeSynchronously(_, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/true); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_3Test, executePreferSyncFailure) { + // setup failure + const auto ret = + makeExecuteSynchronously_1_3Return(V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + EXPECT_CALL(*kMockPreparedModel, executeSynchronously_1_3(_, _, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/true); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_0Test, executeFencedFailure) { + // setup failure + const auto ret = makeExecuteReturn(V1_0::ErrorStatus::GENERAL_FAILURE, + V1_0::ErrorStatus::GENERAL_FAILURE); + EXPECT_CALL(*kMockPreparedModel, execute(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, syncFence, dispatchCallback, timing] = + kPreparedModel->executeFenced({}, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, dispatchCallback.get()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_1Test, executeFencedFailure) { + // setup failure + const auto ret = makeExecuteReturn(V1_0::ErrorStatus::GENERAL_FAILURE, + V1_0::ErrorStatus::GENERAL_FAILURE); + EXPECT_CALL(*kMockPreparedModel, execute(_, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, syncFence, dispatchCallback, timing] = + kPreparedModel->executeFenced({}, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, dispatchCallback.get()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_2Test, executeFencedFailure) { + // setup failure + const auto ret = + makeExecuteSynchronouslyReturn(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + EXPECT_CALL(*kMockPreparedModel, executeSynchronously(_, _, _)).Times(1).WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, syncFence, dispatchCallback, timing] = + kPreparedModel->executeFenced({}, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, dispatchCallback.get()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_3Test, executeFencedFailure) { + // setup failure + auto memory = allocateSharedMemory(4); + hidl_handle fakeSyncFence(memory.handle()); + const sp callback = new MockFencedExecutionCallback(); + const auto ret = + makeExecuteFencedReturn(V1_3::ErrorStatus::GENERAL_FAILURE, fakeSyncFence, callback); + EXPECT_CALL(*kMockPreparedModel, executeFenced(_, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const auto [resultCode, syncFence, dispatchCallback, timing] = + kPreparedModel->executeFenced({}, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, dispatchCallback.get()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_2Test, configureExecutionBurstFailure) { + // setup failure + const sp burstContext = new MockBurstContext(); + const auto ret = makeConfigureExecutionBurst(V1_0::ErrorStatus::GENERAL_FAILURE, burstContext); + EXPECT_CALL(*kMockPreparedModel, configureExecutionBurst(_, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const auto executionBurstController = + kPreparedModel->configureExecutionBurst(/*preferPowerOverLatency=*/false); + + // verify failure + EXPECT_EQ(nullptr, executionBurstController); +} + +TEST_F(VersionedIPreparedModelV1_3Test, configureExecutionBurstFailure) { + // setup failure + const sp burstContext = new MockBurstContext(); + const auto ret = makeConfigureExecutionBurst(V1_0::ErrorStatus::GENERAL_FAILURE, burstContext); + EXPECT_CALL(*kMockPreparedModel, configureExecutionBurst(_, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const auto executionBurstController = + kPreparedModel->configureExecutionBurst(/*preferPowerOverLatency=*/false); + + // verify failure + EXPECT_EQ(nullptr, executionBurstController); +} + +TEST_F(VersionedIPreparedModelV1_2Test, configureExecutionBurstNullptrError) { + // setup failure + const auto ret = makeConfigureExecutionBurst(V1_0::ErrorStatus::NONE, nullptr); + EXPECT_CALL(*kMockPreparedModel, configureExecutionBurst(_, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const auto executionBurstController = + kPreparedModel->configureExecutionBurst(/*preferPowerOverLatency=*/false); + + // verify failure + EXPECT_EQ(nullptr, executionBurstController); +} + +TEST_F(VersionedIPreparedModelV1_3Test, configureExecutionBurstNullptrError) { + // setup failure + const auto ret = makeConfigureExecutionBurst(V1_0::ErrorStatus::NONE, nullptr); + EXPECT_CALL(*kMockPreparedModel, configureExecutionBurst(_, _, _, _)) + .Times(1) + .WillOnce(Invoke(ret)); + + // run test + const auto executionBurstController = + kPreparedModel->configureExecutionBurst(/*preferPowerOverLatency=*/false); + + // verify failure + EXPECT_EQ(nullptr, executionBurstController); +} + +// Simulate transport failure + +TEST_F(VersionedIPreparedModelV1_0Test, executeAsyncTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, execute(_, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_1Test, executeAsyncTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, execute(_, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_2Test, executeAsyncTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, execute_1_2(_, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_3Test, executeAsyncTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, execute_1_3(_, _, _, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_0Test, executePreferSyncTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, execute(_, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/true); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_1Test, executePreferSyncTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, execute(_, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/true); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_2Test, executePreferSyncTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, executeSynchronously(_, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/true); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_3Test, executePreferSyncTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, executeSynchronously_1_3(_, _, _, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/true); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_0Test, executeFencedTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, execute(_, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto [resultCode, syncFence, dispatchCallback, timing] = + kPreparedModel->executeFenced({}, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, dispatchCallback.get()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_1Test, executeFencedTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, execute(_, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto [resultCode, syncFence, dispatchCallback, timing] = + kPreparedModel->executeFenced({}, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, dispatchCallback.get()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_2Test, executeFencedTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, executeSynchronously(_, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto [resultCode, syncFence, dispatchCallback, timing] = + kPreparedModel->executeFenced({}, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, dispatchCallback.get()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_3Test, executeFencedTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, executeFenced(_, _, _, _, _, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto [resultCode, syncFence, dispatchCallback, timing] = + kPreparedModel->executeFenced({}, {}, {}, {}, {}, {}); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode); + EXPECT_EQ(nullptr, syncFence.getNativeHandle()); + EXPECT_EQ(nullptr, dispatchCallback.get()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_2Test, configureExecutionBurstTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, configureExecutionBurst(_, _, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto executionBurstController = + kPreparedModel->configureExecutionBurst(/*preferPowerOverLatency=*/false); + + // verify failure + EXPECT_EQ(nullptr, executionBurstController); +} + +TEST_F(VersionedIPreparedModelV1_3Test, configureExecutionBurstTransportFailure) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, configureExecutionBurst(_, _, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure)); + + // run test + const auto executionBurstController = + kPreparedModel->configureExecutionBurst(/*preferPowerOverLatency=*/false); + + // verify failure + EXPECT_EQ(nullptr, executionBurstController); +} + +// Simulate service crash + +TEST_F(VersionedIPreparedModelV1_0Test, executeAsyncLaunchCrash) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, execute(_, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_DEAD_OBJECT, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_1Test, executeAsyncLaunchCrash) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, execute(_, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_DEAD_OBJECT, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_2Test, executeAsyncLaunchCrash) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, execute_1_2(_, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_DEAD_OBJECT, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_3Test, executeAsyncLaunchCrash) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, execute_1_3(_, _, _, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_DEAD_OBJECT, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_2Test, executePreferSyncCrash) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, executeSynchronously(_, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/true); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_DEAD_OBJECT, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelV1_3Test, executePreferSyncCrash) { + // setup failure + EXPECT_CALL(*kMockPreparedModel, executeSynchronously_1_3(_, _, _, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/true); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_DEAD_OBJECT, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +TEST_F(VersionedIPreparedModelMockTest, executeAsyncReturnCrash) { + // setup failure + const auto ret = [this]() -> Return { + kMockPreparedModel->simulateCrash(); + return V1_3::ErrorStatus::NONE; + }; + EXPECT_CALL(*kMockPreparedModel, execute_1_3(_, _, _, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(ret)); + + // run test + const auto [resultCode, outputShapes, timing] = + kPreparedModel->execute({}, {}, {}, {}, /*preferSynchronous=*/false); + + // verify failure + EXPECT_EQ(ANEURALNETWORKS_DEAD_OBJECT, resultCode); + EXPECT_EQ(0u, outputShapes.size()); + EXPECT_EQ(kNoTiming, timing); +} + +} // namespace +} // namespace android::nn -- cgit v1.2.3