Add negative tests to the Neuralnetworks HAL

This CL adds negative tests to:
* IDevice::getSupportedOperations
* IDevice::prepareModel
* IPreparedModel::execute

It does not make sense to have negative tests for the remaining HAL
entries:
* IDevice::getStatus (all returned values are valid)
* IDevice::getCapabilities (no input or state)
* IEvent::notify (synchronization callback primitive)

Bug: 63905942
Test: mm, running on sample driver has expected output
Change-Id: Ia3cf5ce05dd07ff3f688395b8d0e581851909028
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 2318430..89e1021 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -19,6 +19,7 @@
     srcs: [
         "Event.cpp",
         "GeneratedTestHarness.cpp",
+        "Models.cpp",
         "VtsHalNeuralnetworksV1_0TargetTest.cpp",
     ],
     defaults: ["VtsHalTargetTestDefaults"],
diff --git a/neuralnetworks/1.0/vts/functional/Models.cpp b/neuralnetworks/1.0/vts/functional/Models.cpp
new file mode 100644
index 0000000..9802f62
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/Models.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "Models.h"
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_0 {
+namespace vts {
+namespace functional {
+
+// create a valid model
+Model createValidTestModel() {
+    const std::vector<float> operand2Data = {5.0f, 6.0f, 7.0f, 8.0f};
+    const uint32_t size = operand2Data.size() * sizeof(float);
+
+    const uint32_t operand1 = 0;
+    const uint32_t operand2 = 1;
+    const uint32_t operand3 = 2;
+    const uint32_t operand4 = 3;
+
+    const std::vector<Operand> operands = {
+        {
+            .type = OperandType::TENSOR_FLOAT32,
+            .dimensions = {1, 2, 2, 1},
+            .numberOfConsumers = 1,
+            .scale = 0.0f,
+            .zeroPoint = 0,
+            .lifetime = OperandLifeTime::MODEL_INPUT,
+            .location = {.poolIndex = 0, .offset = 0, .length = 0},
+        },
+        {
+            .type = OperandType::TENSOR_FLOAT32,
+            .dimensions = {1, 2, 2, 1},
+            .numberOfConsumers = 1,
+            .scale = 0.0f,
+            .zeroPoint = 0,
+            .lifetime = OperandLifeTime::CONSTANT_COPY,
+            .location = {.poolIndex = 0, .offset = 0, .length = size},
+        },
+        {
+            .type = OperandType::INT32,
+            .dimensions = {},
+            .numberOfConsumers = 1,
+            .scale = 0.0f,
+            .zeroPoint = 0,
+            .lifetime = OperandLifeTime::CONSTANT_COPY,
+            .location = {.poolIndex = 0, .offset = size, .length = sizeof(int32_t)},
+        },
+        {
+            .type = OperandType::TENSOR_FLOAT32,
+            .dimensions = {1, 2, 2, 1},
+            .numberOfConsumers = 0,
+            .scale = 0.0f,
+            .zeroPoint = 0,
+            .lifetime = OperandLifeTime::MODEL_OUTPUT,
+            .location = {.poolIndex = 0, .offset = 0, .length = 0},
+        },
+    };
+
+    const std::vector<Operation> operations = {{
+        .opTuple = {OperationType::ADD, OperandType::TENSOR_FLOAT32},
+        .inputs = {operand1, operand2, operand3},
+        .outputs = {operand4},
+    }};
+
+    const std::vector<uint32_t> inputIndexes = {operand1};
+    const std::vector<uint32_t> outputIndexes = {operand4};
+    std::vector<uint8_t> operandValues(
+        reinterpret_cast<const uint8_t*>(operand2Data.data()),
+        reinterpret_cast<const uint8_t*>(operand2Data.data()) + size);
+    int32_t activation[1] = {static_cast<int32_t>(FusedActivationFunc::NONE)};
+    operandValues.insert(operandValues.end(), reinterpret_cast<const uint8_t*>(&activation[0]),
+                         reinterpret_cast<const uint8_t*>(&activation[1]));
+
+    const std::vector<hidl_memory> pools = {};
+
+    return {
+        .operands = operands,
+        .operations = operations,
+        .inputIndexes = inputIndexes,
+        .outputIndexes = outputIndexes,
+        .operandValues = operandValues,
+        .pools = pools,
+    };
+}
+
+// create first invalid model
+Model createInvalidTestModel1() {
+    Model model = createValidTestModel();
+    model.operations[0].opTuple = {static_cast<OperationType>(0xDEADBEEF) /* INVALID */,
+                                   OperandType::TENSOR_FLOAT32};
+    return model;
+}
+
+// create second invalid model
+Model createInvalidTestModel2() {
+    Model model = createValidTestModel();
+    const uint32_t operand1 = 0;
+    const uint32_t operand5 = 4;  // INVALID OPERAND
+    model.inputIndexes = std::vector<uint32_t>({operand1, operand5 /* INVALID OPERAND */});
+    return model;
+}
+
+// allocator helper
+hidl_memory allocateSharedMemory(int64_t size, const std::string& type = "ashmem") {
+    hidl_memory memory;
+
+    sp<IAllocator> allocator = IAllocator::getService(type);
+    if (!allocator.get()) {
+        return {};
+    }
+
+    Return<void> ret = allocator->allocate(size, [&](bool success, const hidl_memory& mem) {
+        ASSERT_TRUE(success);
+        memory = mem;
+    });
+    if (!ret.isOk()) {
+        return {};
+    }
+
+    return memory;
+}
+
+// create a valid request
+Request createValidTestRequest() {
+    std::vector<float> inputData = {1.0f, 2.0f, 3.0f, 4.0f};
+    std::vector<float> outputData = {-1.0f, -1.0f, -1.0f, -1.0f};
+    const uint32_t INPUT = 0;
+    const uint32_t OUTPUT = 1;
+
+    // prepare inputs
+    uint32_t inputSize = static_cast<uint32_t>(inputData.size() * sizeof(float));
+    uint32_t outputSize = static_cast<uint32_t>(outputData.size() * sizeof(float));
+    std::vector<RequestArgument> inputs = {{
+        .location = {.poolIndex = INPUT, .offset = 0, .length = inputSize}, .dimensions = {},
+    }};
+    std::vector<RequestArgument> outputs = {{
+        .location = {.poolIndex = OUTPUT, .offset = 0, .length = outputSize}, .dimensions = {},
+    }};
+    std::vector<hidl_memory> pools = {allocateSharedMemory(inputSize),
+                                      allocateSharedMemory(outputSize)};
+    if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
+        return {};
+    }
+
+    // load data
+    sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
+    sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]);
+    if (inputMemory.get() == nullptr || outputMemory.get() == nullptr) {
+        return {};
+    }
+    float* inputPtr = reinterpret_cast<float*>(static_cast<void*>(inputMemory->getPointer()));
+    float* outputPtr = reinterpret_cast<float*>(static_cast<void*>(outputMemory->getPointer()));
+    if (inputPtr == nullptr || outputPtr == nullptr) {
+        return {};
+    }
+    inputMemory->update();
+    outputMemory->update();
+    std::copy(inputData.begin(), inputData.end(), inputPtr);
+    std::copy(outputData.begin(), outputData.end(), outputPtr);
+    inputMemory->commit();
+    outputMemory->commit();
+
+    return {.inputs = inputs, .outputs = outputs, .pools = pools};
+}
+
+// create first invalid request
+Request createInvalidTestRequest1() {
+    Request request = createValidTestRequest();
+    const uint32_t INVALID = 2;
+    std::vector<float> inputData = {1.0f, 2.0f, 3.0f, 4.0f};
+    uint32_t inputSize = static_cast<uint32_t>(inputData.size() * sizeof(float));
+    request.inputs[0].location = {
+        .poolIndex = INVALID /* INVALID */, .offset = 0, .length = inputSize};
+    return request;
+}
+
+// create second invalid request
+Request createInvalidTestRequest2() {
+    Request request = createValidTestRequest();
+    request.inputs[0].dimensions = std::vector<uint32_t>({1, 2, 3, 4, 5, 6, 7, 8} /* INVALID */);
+    return request;
+}
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace neuralnetworks
+}  // namespace hardware
+}  // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/Models.h b/neuralnetworks/1.0/vts/functional/Models.h
new file mode 100644
index 0000000..e0d57d5
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/Models.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworksV1_0TargetTest.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_0 {
+namespace vts {
+namespace functional {
+
+// create the model
+Model createValidTestModel();
+Model createInvalidTestModel1();
+Model createInvalidTestModel2();
+
+// create the request
+Request createValidTestRequest();
+Request createInvalidTestRequest1();
+Request createInvalidTestRequest2();
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace neuralnetworks
+}  // namespace hardware
+}  // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp
index 453e3e5..59d66ba 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp
@@ -18,6 +18,7 @@
 
 #include "VtsHalNeuralnetworksV1_0TargetTest.h"
 #include "Event.h"
+#include "Models.h"
 #include "TestHarness.h"
 
 #include <android-base/logging.h>
@@ -65,6 +66,32 @@
 
 void NeuralnetworksHidlTest::TearDown() {}
 
+sp<IPreparedModel> NeuralnetworksHidlTest::doPrepareModelShortcut(const Model& model) {
+    sp<IPreparedModel> preparedModel;
+    ErrorStatus prepareStatus;
+    sp<Event> preparationEvent = new Event();
+    if (preparationEvent.get() == nullptr) {
+        return nullptr;
+    }
+
+    Return<void> prepareRet = device->prepareModel(
+        model, preparationEvent, [&](ErrorStatus status, const sp<IPreparedModel>& prepared) {
+            prepareStatus = status;
+            preparedModel = prepared;
+        });
+
+    if (!prepareRet.isOk() || prepareStatus != ErrorStatus::NONE ||
+        preparedModel.get() == nullptr) {
+        return nullptr;
+    }
+    Event::Status eventStatus = preparationEvent->wait();
+    if (eventStatus != Event::Status::SUCCESS) {
+        return nullptr;
+    }
+
+    return preparedModel;
+}
+
 // create device test
 TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
 
@@ -91,107 +118,9 @@
     EXPECT_TRUE(ret.isOk());
 }
 
-namespace {
-// create the model
-Model createTestModel() {
-    const std::vector<float> operand2Data = {5.0f, 6.0f, 7.0f, 8.0f};
-    const uint32_t size = operand2Data.size() * sizeof(float);
-
-    const uint32_t operand1 = 0;
-    const uint32_t operand2 = 1;
-    const uint32_t operand3 = 2;
-    const uint32_t operand4 = 3;
-
-    const std::vector<Operand> operands = {
-        {
-            .type = OperandType::TENSOR_FLOAT32,
-            .dimensions = {1, 2, 2, 1},
-            .numberOfConsumers = 1,
-            .scale = 0.0f,
-            .zeroPoint = 0,
-            .lifetime = OperandLifeTime::MODEL_INPUT,
-            .location = {.poolIndex = 0, .offset = 0, .length = 0},
-        },
-        {
-            .type = OperandType::TENSOR_FLOAT32,
-            .dimensions = {1, 2, 2, 1},
-            .numberOfConsumers = 1,
-            .scale = 0.0f,
-            .zeroPoint = 0,
-            .lifetime = OperandLifeTime::CONSTANT_COPY,
-            .location = {.poolIndex = 0, .offset = 0, .length = size},
-        },
-        {
-            .type = OperandType::INT32,
-            .dimensions = {},
-            .numberOfConsumers = 1,
-            .scale = 0.0f,
-            .zeroPoint = 0,
-            .lifetime = OperandLifeTime::CONSTANT_COPY,
-            .location = {.poolIndex = 0, .offset = size, .length = sizeof(int32_t)},
-        },
-        {
-            .type = OperandType::TENSOR_FLOAT32,
-            .dimensions = {1, 2, 2, 1},
-            .numberOfConsumers = 0,
-            .scale = 0.0f,
-            .zeroPoint = 0,
-            .lifetime = OperandLifeTime::MODEL_OUTPUT,
-            .location = {.poolIndex = 0, .offset = 0, .length = 0},
-        },
-    };
-
-    const std::vector<Operation> operations = {{
-        .opTuple = {OperationType::ADD, OperandType::TENSOR_FLOAT32},
-        .inputs = {operand1, operand2, operand3},
-        .outputs = {operand4},
-    }};
-
-    const std::vector<uint32_t> inputIndexes = {operand1};
-    const std::vector<uint32_t> outputIndexes = {operand4};
-    std::vector<uint8_t> operandValues(
-        reinterpret_cast<const uint8_t*>(operand2Data.data()),
-        reinterpret_cast<const uint8_t*>(operand2Data.data()) + size);
-    int32_t activation[1] = {static_cast<int32_t>(FusedActivationFunc::NONE)};
-    operandValues.insert(operandValues.end(), reinterpret_cast<const uint8_t*>(&activation[0]),
-                         reinterpret_cast<const uint8_t*>(&activation[1]));
-
-    const std::vector<hidl_memory> pools = {};
-
-    return {
-        .operands = operands,
-        .operations = operations,
-        .inputIndexes = inputIndexes,
-        .outputIndexes = outputIndexes,
-        .operandValues = operandValues,
-        .pools = pools,
-    };
-}
-}  // anonymous namespace
-
-// allocator helper
-hidl_memory allocateSharedMemory(int64_t size, const std::string& type = "ashmem") {
-    hidl_memory memory;
-
-    sp<IAllocator> allocator = IAllocator::getService(type);
-    if (!allocator.get()) {
-        return {};
-    }
-
-    Return<void> ret = allocator->allocate(size, [&](bool success, const hidl_memory& mem) {
-        ASSERT_TRUE(success);
-        memory = mem;
-    });
-    if (!ret.isOk()) {
-        return {};
-    }
-
-    return memory;
-}
-
-// supported subgraph test
-TEST_F(NeuralnetworksHidlTest, SupportedOperationsTest) {
-    Model model = createTestModel();
+// supported operations positive test
+TEST_F(NeuralnetworksHidlTest, SupportedOperationsPositiveTest) {
+    Model model = createValidTestModel();
     Return<void> ret = device->getSupportedOperations(
         model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
             EXPECT_EQ(ErrorStatus::NONE, status);
@@ -200,76 +129,126 @@
     EXPECT_TRUE(ret.isOk());
 }
 
-// execute simple graph
-TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphTest) {
-    std::vector<float> inputData = {1.0f, 2.0f, 3.0f, 4.0f};
-    std::vector<float> outputData = {-1.0f, -1.0f, -1.0f, -1.0f};
-    std::vector<float> expectedData = {6.0f, 8.0f, 10.0f, 12.0f};
-    const uint32_t INPUT = 0;
-    const uint32_t OUTPUT = 1;
+// supported operations negative test 1
+TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest1) {
+    Model model = createInvalidTestModel1();
+    Return<void> ret = device->getSupportedOperations(
+        model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
+            EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+            (void)supported;
+        });
+    EXPECT_TRUE(ret.isOk());
+}
 
-    // prepare request
-    Model model = createTestModel();
-    sp<IPreparedModel> preparedModel;
+// supported operations negative test 2
+TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest2) {
+    Model model = createInvalidTestModel2();
+    Return<void> ret = device->getSupportedOperations(
+        model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
+            EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+            (void)supported;
+        });
+    EXPECT_TRUE(ret.isOk());
+}
+
+// prepare simple model positive test
+TEST_F(NeuralnetworksHidlTest, SimplePrepareModelPositiveTest) {
+    Model model = createValidTestModel();
     sp<Event> preparationEvent = new Event();
     ASSERT_NE(nullptr, preparationEvent.get());
     Return<void> prepareRet = device->prepareModel(
         model, preparationEvent, [&](ErrorStatus status, const sp<IPreparedModel>& prepared) {
             EXPECT_EQ(ErrorStatus::NONE, status);
-            preparedModel = prepared;
+            (void)prepared;
         });
     ASSERT_TRUE(prepareRet.isOk());
+}
+
+// prepare simple model negative test 1
+TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest1) {
+    Model model = createInvalidTestModel1();
+    sp<Event> preparationEvent = new Event();
+    ASSERT_NE(nullptr, preparationEvent.get());
+    Return<void> prepareRet = device->prepareModel(
+        model, preparationEvent, [&](ErrorStatus status, const sp<IPreparedModel>& prepared) {
+            EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+            (void)prepared;
+        });
+    ASSERT_TRUE(prepareRet.isOk());
+}
+
+// prepare simple model negative test 2
+TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest2) {
+    Model model = createInvalidTestModel2();
+    sp<Event> preparationEvent = new Event();
+    ASSERT_NE(nullptr, preparationEvent.get());
+    Return<void> prepareRet = device->prepareModel(
+        model, preparationEvent, [&](ErrorStatus status, const sp<IPreparedModel>& prepared) {
+            EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+            (void)prepared;
+        });
+    ASSERT_TRUE(prepareRet.isOk());
+}
+
+// execute simple graph positive test
+TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphPositiveTest) {
+    Model model = createValidTestModel();
+    sp<IPreparedModel> preparedModel = doPrepareModelShortcut(model);
     ASSERT_NE(nullptr, preparedModel.get());
-    Event::Status preparationStatus = preparationEvent->wait();
-    EXPECT_EQ(Event::Status::SUCCESS, preparationStatus);
+    Request request = createValidTestRequest();
 
-    // prepare inputs
-    uint32_t inputSize = static_cast<uint32_t>(inputData.size() * sizeof(float));
-    uint32_t outputSize = static_cast<uint32_t>(outputData.size() * sizeof(float));
-    std::vector<RequestArgument> inputs = {{
-        .location = {.poolIndex = INPUT, .offset = 0, .length = inputSize}, .dimensions = {},
-    }};
-    std::vector<RequestArgument> outputs = {{
-        .location = {.poolIndex = OUTPUT, .offset = 0, .length = outputSize}, .dimensions = {},
-    }};
-    std::vector<hidl_memory> pools = {allocateSharedMemory(inputSize),
-                                      allocateSharedMemory(outputSize)};
-    ASSERT_NE(0ull, pools[INPUT].size());
-    ASSERT_NE(0ull, pools[OUTPUT].size());
-
-    // load data
-    sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
-    sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]);
-    ASSERT_NE(nullptr, inputMemory.get());
-    ASSERT_NE(nullptr, outputMemory.get());
-    float* inputPtr = reinterpret_cast<float*>(static_cast<void*>(inputMemory->getPointer()));
-    float* outputPtr = reinterpret_cast<float*>(static_cast<void*>(outputMemory->getPointer()));
-    ASSERT_NE(nullptr, inputPtr);
-    ASSERT_NE(nullptr, outputPtr);
-    inputMemory->update();
-    outputMemory->update();
-    std::copy(inputData.begin(), inputData.end(), inputPtr);
-    std::copy(outputData.begin(), outputData.end(), outputPtr);
-    inputMemory->commit();
-    outputMemory->commit();
-
-    // execute request
     sp<Event> executionEvent = new Event();
     ASSERT_NE(nullptr, executionEvent.get());
-    Return<ErrorStatus> executeStatus = preparedModel->execute(
-        {.inputs = inputs, .outputs = outputs, .pools = pools}, executionEvent);
+    Return<ErrorStatus> executeStatus = preparedModel->execute(request, executionEvent);
     ASSERT_TRUE(executeStatus.isOk());
     EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executeStatus));
     Event::Status eventStatus = executionEvent->wait();
     EXPECT_EQ(Event::Status::SUCCESS, eventStatus);
 
-    // validate results { 1+5, 2+6, 3+7, 4+8 }
+    std::vector<float> outputData = {-1.0f, -1.0f, -1.0f, -1.0f};
+    std::vector<float> expectedData = {6.0f, 8.0f, 10.0f, 12.0f};
+    const uint32_t OUTPUT = 1;
+
+    sp<IMemory> outputMemory = mapMemory(request.pools[OUTPUT]);
+    ASSERT_NE(nullptr, outputMemory.get());
+    float* outputPtr = reinterpret_cast<float*>(static_cast<void*>(outputMemory->getPointer()));
+    ASSERT_NE(nullptr, outputPtr);
     outputMemory->read();
     std::copy(outputPtr, outputPtr + outputData.size(), outputData.begin());
     outputMemory->commit();
     EXPECT_EQ(expectedData, outputData);
 }
 
+// execute simple graph negative test 1
+TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest1) {
+    Model model = createValidTestModel();
+    sp<IPreparedModel> preparedModel = doPrepareModelShortcut(model);
+    ASSERT_NE(nullptr, preparedModel.get());
+    Request request = createInvalidTestRequest1();
+
+    sp<Event> executionEvent = new Event();
+    ASSERT_NE(nullptr, executionEvent.get());
+    Return<ErrorStatus> executeStatus = preparedModel->execute(request, executionEvent);
+    ASSERT_TRUE(executeStatus.isOk());
+    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeStatus));
+    executionEvent->wait();
+}
+
+// execute simple graph negative test 2
+TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest2) {
+    Model model = createValidTestModel();
+    sp<IPreparedModel> preparedModel = doPrepareModelShortcut(model);
+    ASSERT_NE(nullptr, preparedModel.get());
+    Request request = createInvalidTestRequest2();
+
+    sp<Event> executionEvent = new Event();
+    ASSERT_NE(nullptr, executionEvent.get());
+    Return<ErrorStatus> executeStatus = preparedModel->execute(request, executionEvent);
+    ASSERT_TRUE(executeStatus.isOk());
+    EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeStatus));
+    executionEvent->wait();
+}
+
 // Mixed-typed examples
 typedef MixedTypedExampleType MixedTypedExample;
 
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.h
index 9c56e6a..1b3b334 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.h
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.h
@@ -72,6 +72,8 @@
     void SetUp() override;
     void TearDown() override;
 
+    sp<IPreparedModel> doPrepareModelShortcut(const Model& model);
+
     sp<IDevice> device;
 };