Merge "Adding the interface file for the prebuilt computepipe graph execution library."
diff --git a/computepipe/runner/include/MemHandle.h b/computepipe/runner/include/MemHandle.h
index 19c5c73..bd9198d 100644
--- a/computepipe/runner/include/MemHandle.h
+++ b/computepipe/runner/include/MemHandle.h
@@ -24,16 +24,18 @@
class MemHandle {
public:
+ /* Retrieve stream Id */
+ virtual int getStreamId() const = 0;
/* Retrieve packet type */
- virtual proto::PacketType getType() = 0;
+ virtual proto::PacketType getType() const = 0;
/* Retrieve packet time stamp */
- virtual uint64_t getTimeStamp() = 0;
+ virtual uint64_t getTimeStamp() const = 0;
/* Get size */
- virtual uint32_t getSize() = 0;
+ virtual uint32_t getSize() const = 0;
/* Get data, raw pointer. Only implemented for copy semantics */
- virtual const char* getData() = 0;
+ virtual const char* getData() const = 0;
/* Get native handle. data with zero copy semantics */
- virtual native_handle_t getNativeHandle() = 0;
+ virtual native_handle_t getNativeHandle() const = 0;
virtual ~MemHandle() {
}
diff --git a/computepipe/runner/stream_manager/Factory.cpp b/computepipe/runner/stream_manager/Factory.cpp
index 9a82028..d77016a 100644
--- a/computepipe/runner/stream_manager/Factory.cpp
+++ b/computepipe/runner/stream_manager/Factory.cpp
@@ -31,7 +31,7 @@
const proto::OutputConfig& config, std::function<Status(std::shared_ptr<MemHandle>)>& cb,
uint32_t maxPackets) {
std::unique_ptr<SemanticManager> semanticManager =
- std::make_unique<SemanticManager>(config.stream_name(), config.type());
+ std::make_unique<SemanticManager>(config.stream_name(), config.stream_id(), config.type());
if (semanticManager->setIpcDispatchCallback(cb) != SUCCESS) {
return nullptr;
}
diff --git a/computepipe/runner/stream_manager/SemanticManager.cpp b/computepipe/runner/stream_manager/SemanticManager.cpp
index 2f57dbf..a874b96 100644
--- a/computepipe/runner/stream_manager/SemanticManager.cpp
+++ b/computepipe/runner/stream_manager/SemanticManager.cpp
@@ -10,34 +10,39 @@
namespace runner {
namespace stream_manager {
-proto::PacketType SemanticHandle::getType() {
+proto::PacketType SemanticHandle::getType() const {
return mType;
}
-uint64_t SemanticHandle::getTimeStamp() {
+uint64_t SemanticHandle::getTimeStamp() const {
return mTimestamp;
}
-uint32_t SemanticHandle::getSize() {
+uint32_t SemanticHandle::getSize() const {
return mSize;
}
-const char* SemanticHandle::getData() {
+const char* SemanticHandle::getData() const {
return mData;
}
-native_handle_t SemanticHandle::getNativeHandle() {
+native_handle_t SemanticHandle::getNativeHandle() const {
native_handle_t temp;
temp.numFds = 0;
temp.numInts = 0;
return temp;
}
-Status SemanticHandle::setMemInfo(const char* data, uint32_t size, uint64_t timestamp,
+int SemanticHandle::getStreamId() const {
+ return mStreamId;
+}
+
+Status SemanticHandle::setMemInfo(int streamId, const char* data, uint32_t size, uint64_t timestamp,
const proto::PacketType& type) {
if (data == nullptr || size == 0 || size > kMaxSemanticDataSize) {
return INVALID_ARGUMENT;
}
+ mStreamId = streamId;
mData = (char*)malloc(size);
if (!mData) {
return NO_MEMORY;
@@ -138,7 +143,7 @@
return INTERNAL_ERROR;
}
auto memHandle = std::make_shared<SemanticHandle>();
- auto status = memHandle->setMemInfo(data, size, timestamp, mType);
+ auto status = memHandle->setMemInfo(mStreamId, data, size, timestamp, mType);
if (status != SUCCESS) {
return status;
}
@@ -146,8 +151,8 @@
return SUCCESS;
}
-SemanticManager::SemanticManager(std::string name, const proto::PacketType& type)
- : StreamManager(name, type) {
+SemanticManager::SemanticManager(std::string name, int streamId, const proto::PacketType& type)
+ : StreamManager(name, type), mStreamId(streamId) {
}
} // namespace stream_manager
} // namespace runner
diff --git a/computepipe/runner/stream_manager/SemanticManager.h b/computepipe/runner/stream_manager/SemanticManager.h
index c738718..687e0b9 100644
--- a/computepipe/runner/stream_manager/SemanticManager.h
+++ b/computepipe/runner/stream_manager/SemanticManager.h
@@ -31,17 +31,17 @@
class SemanticHandle : public MemHandle {
public:
static constexpr uint32_t kMaxSemanticDataSize = 1024;
- proto::PacketType getType() override;
- /* Retrieve packet time stamp */
- uint64_t getTimeStamp() override;
- /* Get size */
- uint32_t getSize() override;
- /* Get data, raw pointer. Only implemented for copy semantics */
- const char* getData() override;
- /* Get native handle. data with zero copy semantics */
- native_handle_t getNativeHandle() override;
+ /**
+ * Override mem handle methods
+ */
+ int getStreamId() const override;
+ proto::PacketType getType() const override;
+ uint64_t getTimeStamp() const override;
+ uint32_t getSize() const override;
+ const char* getData() const override;
+ native_handle_t getNativeHandle() const override;
/* set info for the memory. Make a copy */
- Status setMemInfo(const char* data, uint32_t size, uint64_t timestamp,
+ Status setMemInfo(int streamId, const char* data, uint32_t size, uint64_t timestamp,
const proto::PacketType& type);
/* Destroy local copy */
~SemanticHandle();
@@ -51,6 +51,7 @@
uint32_t mSize;
uint64_t mTimestamp;
proto::PacketType mType;
+ int mStreamId;
};
class SemanticManager : public StreamManager, StreamManagerInit {
@@ -69,11 +70,12 @@
Status handleStopWithFlushPhase(const RunnerEvent& e) override;
Status handleStopImmediatePhase(const RunnerEvent& e) override;
- explicit SemanticManager(std::string name, const proto::PacketType& type);
+ explicit SemanticManager(std::string name, int streamId, const proto::PacketType& type);
~SemanticManager() = default;
private:
std::mutex mStateLock;
+ int mStreamId;
std::function<Status(const std::shared_ptr<MemHandle>&)> mDispatchCallback = nullptr;
};
} // namespace stream_manager
diff --git a/computepipe/runner/utils/Android.bp b/computepipe/runner/utils/Android.bp
index 74c6656..a297b47 100644
--- a/computepipe/runner/utils/Android.bp
+++ b/computepipe/runner/utils/Android.bp
@@ -39,7 +39,11 @@
"libprotobuf-cpp-lite",
],
- visibility:["//packages/services/Car/computepipe/runner:__subpackages__"],
+ visibility:[
+ "//packages/services/Car/computepipe/runner:__subpackages__",
+ "//packages/services/Car/computepipe/tests:__subpackages__",
+ ],
+
srcs: [
"InterfaceImpl.cc",
"PipeOptionsConverter.cc",
diff --git a/computepipe/runner/utils/InterfaceImpl.cc b/computepipe/runner/utils/InterfaceImpl.cc
index 67b7bc6..df57d99 100644
--- a/computepipe/runner/utils/InterfaceImpl.cc
+++ b/computepipe/runner/utils/InterfaceImpl.cc
@@ -12,13 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.c
+#define LOG_TAG "RunnerIpcInterface"
+
#include "InterfaceImpl.h"
#include "OutputConfig.pb.h"
#include "PacketDescriptor.pb.h"
#include "PipeOptionsConverter.h"
-#define LOG_TAG "RunnerIpcInterface"
#include <aidl/android/automotive/computepipe/runner/PacketDescriptor.h>
#include <aidl/android/automotive/computepipe/runner/PacketDescriptorPacketType.h>
#include <android-base/logging.h>
@@ -73,13 +74,16 @@
iface->clientDied();
}
-Status ToAidlPacketType(proto::PacketType type, PacketDescriptorPacketType& outType) {
+Status ToAidlPacketType(proto::PacketType type, PacketDescriptorPacketType* outType) {
+ if (outType == nullptr) {
+ return Status::INTERNAL_ERROR;
+ }
switch (type) {
case proto::SEMANTIC_DATA:
- outType = PacketDescriptorPacketType::SEMANTIC_DATA;
+ *outType = PacketDescriptorPacketType::SEMANTIC_DATA;
return Status::SUCCESS;
case proto::PIXEL_DATA:
- outType = PacketDescriptorPacketType::PIXEL_DATA;
+ *outType = PacketDescriptorPacketType::PIXEL_DATA;
return Status::SUCCESS;
default:
LOG(ERROR) << "unknown packet type " << type;
@@ -97,7 +101,7 @@
LOG(ERROR) << "Bad streamId";
return Status::INVALID_ARGUMENT;
}
- Status status = ToAidlPacketType(packetHandle->getType(), desc.type);
+ Status status = ToAidlPacketType(packetHandle->getType(), &desc.type);
if (status != SUCCESS) {
return status;
}
diff --git a/computepipe/runner/utils/RunnerInterface.cc b/computepipe/runner/utils/RunnerInterface.cc
index 66c2bea..0ff7aaf 100644
--- a/computepipe/runner/utils/RunnerInterface.cc
+++ b/computepipe/runner/utils/RunnerInterface.cc
@@ -16,12 +16,12 @@
#include "RunnerInterface.h"
-#include <thread>
-
#include <aidl/android/automotive/computepipe/registry/IPipeRegistration.h>
#include <android/binder_manager.h>
#include <android-base/logging.h>
+#include <thread>
+
namespace android {
namespace automotive {
namespace computepipe {
@@ -45,7 +45,7 @@
return Status::INVALID_ARGUMENT;
}
- mPipeRunner = std::make_shared<InterfaceImpl>(mGraphOptions, mRunnerInterfaceCallbacks);
+ mPipeRunner = ndk::SharedRefBase::make<InterfaceImpl>(mGraphOptions, mRunnerInterfaceCallbacks);
std::thread t(&RunnerInterface::tryRegisterPipeRunner, this);
t.detach();
return Status::SUCCESS;
diff --git a/computepipe/tests/Android.bp b/computepipe/tests/Android.bp
index 18919d2..ec26177 100644
--- a/computepipe/tests/Android.bp
+++ b/computepipe/tests/Android.bp
@@ -41,14 +41,14 @@
test_suites: ["device-tests"],
srcs: [
"PipeQueryTest.cpp",
- "FakeRunner.cpp",
+ "FakeRunner.cpp",
],
static_libs: [
"libgtest",
"libgmock",
],
header_libs: [
- "computepipe_router_headers",
+ "computepipe_router_headers",
],
shared_libs: [
"libbinder",
diff --git a/computepipe/tests/runner/client_interface/Android.bp b/computepipe/tests/runner/client_interface/Android.bp
new file mode 100644
index 0000000..6ee8295
--- /dev/null
+++ b/computepipe/tests/runner/client_interface/Android.bp
@@ -0,0 +1,40 @@
+// 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.
+
+cc_test {
+ name: "clientinterface_test",
+ test_suites: ["device-tests"],
+ srcs: [
+ "ClientInterfaceTest.cc",
+ ],
+ static_libs: [
+ "libgtest",
+ "libgmock",
+ "libcomputepipeprotos",
+ ],
+ header_libs: [
+ "computepipe_router_headers",
+ "computepipe_runner_includes",
+ ],
+ include_dirs: ["packages/services/Car/computepipe"],
+ shared_libs: [
+ "libbinder_ndk",
+ "libutils",
+ "libRunnerInterface",
+ "android.automotive.computepipe.registry-ndk_platform",
+ "android.automotive.computepipe.runner-ndk_platform",
+ "android.automotive.computepipe.runner-ndk_platform",
+ "libprotobuf-cpp-lite",
+ ],
+}
diff --git a/computepipe/tests/runner/client_interface/ClientInterfaceTest.cc b/computepipe/tests/runner/client_interface/ClientInterfaceTest.cc
new file mode 100644
index 0000000..a26be99
--- /dev/null
+++ b/computepipe/tests/runner/client_interface/ClientInterfaceTest.cc
@@ -0,0 +1,362 @@
+// Copyright (C) 2019 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 <aidl/android/automotive/computepipe/registry/BnClientInfo.h>
+#include <aidl/android/automotive/computepipe/registry/IPipeQuery.h>
+#include <aidl/android/automotive/computepipe/registry/IPipeRegistration.h>
+#include <aidl/android/automotive/computepipe/runner/BnPipeStateCallback.h>
+#include <aidl/android/automotive/computepipe/runner/BnPipeStream.h>
+#include <aidl/android/automotive/computepipe/runner/PipeState.h>
+
+#include <android/binder_manager.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <utility>
+
+#include "ConfigurationCommand.pb.h"
+#include "ControlCommand.pb.h"
+#include "MemHandle.h"
+#include "MockMemHandle.h"
+#include "Options.pb.h"
+#include "runner/utils/RunnerInterface.h"
+#include "runner/utils/RunnerInterfaceCallbacks.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace {
+
+using ::aidl::android::automotive::computepipe::registry::BnClientInfo;
+using ::aidl::android::automotive::computepipe::registry::IPipeQuery;
+using ::aidl::android::automotive::computepipe::runner::BnPipeStateCallback;
+using ::aidl::android::automotive::computepipe::runner::BnPipeStream;
+using ::aidl::android::automotive::computepipe::runner::IPipeRunner;
+using ::aidl::android::automotive::computepipe::runner::IPipeStateCallback;
+using ::aidl::android::automotive::computepipe::runner::PacketDescriptor;
+using ::aidl::android::automotive::computepipe::runner::PipeState;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
+using ::testing::AtLeast;
+using ::testing::Return;
+
+const char kRegistryInterfaceName[] = "router";
+
+class RunnerCallbacks {
+ public:
+ Status ControlCommandCallback(const proto::ControlCommand& command) {
+ mLastControlCommand = command;
+ return mStatus;
+ }
+
+ Status ConfigurationCommandCallback(const proto::ConfigurationCommand& command) {
+ mLastConfigurationCommand = command;
+ return mStatus;
+ }
+
+ Status ReleasePacketNotification(const std::shared_ptr<MemHandle>& packet) {
+ mLastPacket = packet;
+ return mStatus;
+ }
+
+ runner_utils::RunnerInterfaceCallbacks GetCallbackObject() {
+ using std::placeholders::_1;
+ std::function<Status(const proto::ControlCommand&)> controlCb =
+ std::bind(&RunnerCallbacks::ControlCommandCallback, this, _1);
+ std::function<Status(const proto::ConfigurationCommand&)> configCb =
+ std::bind(&RunnerCallbacks::ConfigurationCommandCallback, this, _1);
+ std::function<Status(const std::shared_ptr<MemHandle>&)> packetCb =
+ std::bind(&RunnerCallbacks::ReleasePacketNotification, this, _1);
+ return runner_utils::RunnerInterfaceCallbacks(controlCb, configCb, packetCb);
+ }
+
+ void SetReturnStatus(Status status) {
+ mStatus = status;
+ }
+
+ proto::ControlCommand mLastControlCommand;
+ proto::ConfigurationCommand mLastConfigurationCommand;
+ std::shared_ptr<MemHandle> mLastPacket = nullptr;
+ Status mStatus = Status::SUCCESS;
+};
+
+class StateChangeCallback : public BnPipeStateCallback {
+ public:
+ ScopedAStatus handleState(PipeState state) {
+ mState = state;
+ return ScopedAStatus::ok();
+ }
+ PipeState mState = PipeState::RESET;
+};
+
+class StreamCallback : public BnPipeStream {
+ public:
+ ScopedAStatus deliverPacket(const PacketDescriptor& in_packet) override {
+ data = in_packet.data;
+ timestamp = in_packet.sourceTimeStampMillis;
+ return ScopedAStatus::ok();
+ }
+ std::string data;
+ uint64_t timestamp;
+};
+
+class ClientInfo : public BnClientInfo {
+ public:
+ ScopedAStatus getClientId(int32_t* _aidl_return) {
+ if (_aidl_return) {
+ *_aidl_return = 0;
+ return ScopedAStatus::ok();
+ }
+ return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+ }
+};
+
+class ClientInterface : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ const std::string graphName = "graph1";
+ proto::Options options;
+ options.set_graph_name(graphName);
+ mRunnerInterface = std::make_unique<runner_utils::RunnerInterface>(
+ options, mCallbacks.GetCallbackObject());
+
+ // Register the instance with router.
+ EXPECT_EQ(mRunnerInterface->init(), Status::SUCCESS);
+
+ // Init is not a blocking call, so sleep for 3 seconds to allow the runner to register with
+ // router.
+ sleep(3);
+
+ // Retrieve router query instance from service manager.
+ std::string instanceName =
+ std::string() + IPipeQuery::descriptor + "/" + kRegistryInterfaceName;
+ ndk::SpAIBinder binder(AServiceManager_getService(instanceName.c_str()));
+ ASSERT_TRUE(binder.get() != nullptr);
+ std::shared_ptr<IPipeQuery> queryService = IPipeQuery::fromBinder(binder);
+
+ // Retrieve pipe runner instance from the router.
+ std::shared_ptr<ClientInfo> clientInfo = ndk::SharedRefBase::make<ClientInfo>();
+ ASSERT_TRUE(queryService->getPipeRunner(graphName, clientInfo, &mPipeRunner).isOk());
+ }
+
+ RunnerCallbacks mCallbacks;
+ std::shared_ptr<runner_utils::RunnerInterface> mRunnerInterface = nullptr;
+ std::shared_ptr<IPipeRunner> mPipeRunner = nullptr;
+};
+
+TEST_F(ClientInterface, TestSetConfiguration) {
+ // Configure runner to return success.
+ mCallbacks.SetReturnStatus(Status::SUCCESS);
+
+ // Initialize pipe runner.
+ std::shared_ptr<StateChangeCallback> stateCallback =
+ ndk::SharedRefBase::make<StateChangeCallback>();
+ EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
+
+ // Test that set input source returns ok status.
+ EXPECT_TRUE(mPipeRunner->setPipeInputSource(1).isOk());
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.has_set_input_source(), true);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.set_input_source().source_id(), 1);
+
+ // Test that set offload option returns ok status.
+ EXPECT_TRUE(mPipeRunner->setPipeOffloadOptions(5).isOk());
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.has_set_offload_offload(), true);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.set_offload_offload().offload_option_id(), 5);
+
+ // Test that set termination option returns ok status.
+ EXPECT_TRUE(mPipeRunner->setPipeTermination(3).isOk());
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.has_set_termination_option(), true);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.set_termination_option().termination_option_id(),
+ 3);
+
+ // Test that set output callback returns ok status.
+ std::shared_ptr<StreamCallback> streamCb = ndk::SharedRefBase::make<StreamCallback>();
+ EXPECT_TRUE(mPipeRunner->setPipeOutputConfig(0, 10, streamCb).isOk());
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.has_set_output_stream(), true);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.set_output_stream().stream_id(), 0);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.set_output_stream().max_inflight_packets_count(),
+ 10);
+
+ // Release runner here. This should remove registry entry from router registry.
+ mRunnerInterface.reset();
+}
+
+TEST_F(ClientInterface, TestSetConfigurationError) {
+ ScopedAStatus status;
+
+ // Configure runner to return error.
+ mCallbacks.SetReturnStatus(Status::INTERNAL_ERROR);
+
+ // Initialize pipe runner.
+ std::shared_ptr<StateChangeCallback> stateCallback =
+ ndk::SharedRefBase::make<StateChangeCallback>();
+ EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
+
+ // Test that set input source returns error status.
+ status = mPipeRunner->setPipeInputSource(1);
+ EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.has_set_input_source(), true);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.set_input_source().source_id(), 1);
+
+ // Test that set offload option returns error status.
+ status = mPipeRunner->setPipeOffloadOptions(5);
+ EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.has_set_offload_offload(), true);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.set_offload_offload().offload_option_id(), 5);
+
+ // Test that set termination option returns error status.
+ status = mPipeRunner->setPipeTermination(3);
+ EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.has_set_termination_option(), true);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.set_termination_option().termination_option_id(),
+ 3);
+
+ // Test that set output callback returns error status.
+ std::shared_ptr<StreamCallback> streamCb = ndk::SharedRefBase::make<StreamCallback>();
+ status = mPipeRunner->setPipeOutputConfig(0, 10, streamCb);
+ EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.has_set_output_stream(), true);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.set_output_stream().stream_id(), 0);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.set_output_stream().max_inflight_packets_count(),
+ 10);
+
+ // Release runner here. This should remove registry entry from router registry.
+ mRunnerInterface.reset();
+}
+
+TEST_F(ClientInterface, TestControlCommands) {
+ // Configure runner to return success.
+ mCallbacks.SetReturnStatus(Status::SUCCESS);
+
+ // Initialize pipe runner.
+ std::shared_ptr<StateChangeCallback> stateCallback =
+ ndk::SharedRefBase::make<StateChangeCallback>();
+ EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
+
+ // Test that apply-configs api returns ok status.
+ EXPECT_TRUE(mPipeRunner->applyPipeConfigs().isOk());
+ EXPECT_EQ(mCallbacks.mLastControlCommand.has_apply_configs(), true);
+
+ // Test that set start graph api returns ok status.
+ EXPECT_TRUE(mPipeRunner->startPipe().isOk());
+ EXPECT_EQ(mCallbacks.mLastControlCommand.has_start_graph(), true);
+
+ // Test that set stop graph api returns ok status.
+ EXPECT_TRUE(mPipeRunner->stopPipe().isOk());
+ EXPECT_EQ(mCallbacks.mLastControlCommand.has_stop_graph(), true);
+
+ // Release runner here. This should remove registry entry from router registry.
+ mRunnerInterface.reset();
+}
+
+TEST_F(ClientInterface, TestControlCommandsFailure) {
+ ScopedAStatus status;
+
+ // Configure runner to return error status.
+ mCallbacks.SetReturnStatus(Status::INTERNAL_ERROR);
+
+ // Initialize pipe runner.
+ std::shared_ptr<StateChangeCallback> stateCallback =
+ ndk::SharedRefBase::make<StateChangeCallback>();
+ EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
+
+ // Test that apply-configs api returns error status.
+ status = mPipeRunner->applyPipeConfigs();
+ EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+ EXPECT_EQ(mCallbacks.mLastControlCommand.has_apply_configs(), true);
+
+ // Test that start graph api returns error status.
+ status = mPipeRunner->startPipe();
+ EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+ EXPECT_EQ(mCallbacks.mLastControlCommand.has_start_graph(), true);
+
+ // Test that stop graph api returns error status.
+ status = mPipeRunner->stopPipe();
+ EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+ EXPECT_EQ(mCallbacks.mLastControlCommand.has_stop_graph(), true);
+
+ // Release runner here. This should remove registry entry from router registry.
+ mRunnerInterface.reset();
+}
+
+TEST_F(ClientInterface, TestFailureWithoutInit) {
+ mCallbacks.SetReturnStatus(Status::SUCCESS);
+
+ // Pipe runner is not initalized here, test that a configuration command returns error status.
+ ScopedAStatus status;
+ status = mPipeRunner->setPipeInputSource(1);
+ EXPECT_EQ(status.getExceptionCode(), EX_ILLEGAL_STATE);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.has_set_input_source(), false);
+
+ // Test that a control command returns error status.
+ status = mPipeRunner->applyPipeConfigs();
+ EXPECT_EQ(status.getExceptionCode(), EX_ILLEGAL_STATE);
+ EXPECT_EQ(mCallbacks.mLastControlCommand.has_apply_configs(), false);
+}
+
+TEST_F(ClientInterface, TestStateChangeNotification) {
+ // Create RunnerInterface instance.
+ mCallbacks.SetReturnStatus(Status::SUCCESS);
+
+ // Initialize pipe runner.
+ std::shared_ptr<StateChangeCallback> stateCallback =
+ ndk::SharedRefBase::make<StateChangeCallback>();
+ EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
+
+ // Test that when runner interface is notified of a new state, client callback is invoked with
+ // correct state.
+ GraphState state = RUNNING;
+ EXPECT_EQ(mRunnerInterface->stateUpdateNotification(state), Status::SUCCESS);
+ EXPECT_EQ(stateCallback->mState, PipeState::RUNNING);
+}
+
+TEST_F(ClientInterface, TestPacketDelivery) {
+ // Configure runner to return success state.
+ mCallbacks.SetReturnStatus(Status::SUCCESS);
+
+ // Initialize pipe runner.
+ std::shared_ptr<StateChangeCallback> stateCallback =
+ ndk::SharedRefBase::make<StateChangeCallback>();
+ EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
+
+ // Set callback for stream id 0.
+ std::shared_ptr<StreamCallback> streamCb = ndk::SharedRefBase::make<StreamCallback>();
+ EXPECT_TRUE(mPipeRunner->setPipeOutputConfig(0, 10, streamCb).isOk());
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.has_set_output_stream(), true);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.set_output_stream().stream_id(), 0);
+ EXPECT_EQ(mCallbacks.mLastConfigurationCommand.set_output_stream().max_inflight_packets_count(),
+ 10);
+
+ // Send a packet to client and verify the packet.
+ std::shared_ptr<tests::MockMemHandle> packet = std::make_unique<tests::MockMemHandle>();
+ uint64_t timestamp = 100;
+ const std::string testData = "Test String.";
+ EXPECT_CALL(*packet, getType()).Times(AtLeast(1))
+ .WillRepeatedly(Return(proto::PacketType::SEMANTIC_DATA));
+ EXPECT_CALL(*packet, getTimeStamp()).Times(AtLeast(1))
+ .WillRepeatedly(Return(timestamp));
+ EXPECT_CALL(*packet, getSize()).Times(AtLeast(1))
+ .WillRepeatedly(Return(testData.size()));
+ EXPECT_CALL(*packet, getData()).Times(AtLeast(1))
+ .WillRepeatedly(Return(testData.c_str()));
+ EXPECT_EQ(mRunnerInterface->newPacketNotification(
+ 0, static_cast<std::shared_ptr<MemHandle>>(packet)), Status::SUCCESS);
+ EXPECT_EQ(streamCb->data, packet->getData());
+ EXPECT_EQ(streamCb->timestamp, packet->getTimeStamp());
+}
+
+} // namespace
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
diff --git a/computepipe/tests/runner/client_interface/MockMemHandle.h b/computepipe/tests/runner/client_interface/MockMemHandle.h
new file mode 100644
index 0000000..0bff0e5
--- /dev/null
+++ b/computepipe/tests/runner/client_interface/MockMemHandle.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMPUTEPIPE_TESTS_FAKEMEMHANDLE_H_
+#define COMPUTEPIPE_TESTS_FAKEMEMHANDLE_H_
+
+#include <gmock/gmock.h>
+#include <string>
+
+#include "MemHandle.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace tests {
+
+class MockMemHandle : public MemHandle {
+ public:
+ MOCK_METHOD0(getType, proto::PacketType());
+ MOCK_METHOD0(getTimeStamp, uint64_t());
+ MOCK_METHOD0(getSize, uint32_t());
+ MOCK_METHOD0(getData, const char*());
+ MOCK_METHOD0(getNativeHandle, native_handle_t());
+};
+
+} // namespace tests
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
+
+#endif // COMPUTEPIPE_TESTS_FAKEMEMHANDLE_H_