407 lines
16 KiB
C++
407 lines
16 KiB
C++
// 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 <vector>
|
|
|
|
#include "ConfigurationCommand.pb.h"
|
|
#include "ControlCommand.pb.h"
|
|
#include "MemHandle.h"
|
|
#include "MockEngine.h"
|
|
#include "MockMemHandle.h"
|
|
#include "MockRunnerEvent.h"
|
|
#include "Options.pb.h"
|
|
#include "ProfilingType.pb.h"
|
|
#include "runner/client_interface/AidlClient.h"
|
|
#include "runner/client_interface/include/ClientEngineInterface.h"
|
|
#include "types/Status.h"
|
|
|
|
namespace android {
|
|
namespace automotive {
|
|
namespace computepipe {
|
|
namespace runner {
|
|
namespace client_interface {
|
|
namespace aidl_client {
|
|
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 ::android::automotive::computepipe::runner::tests::MockRunnerEvent;
|
|
using ::android::automotive::computepipe::tests::MockMemHandle;
|
|
using ::ndk::ScopedAStatus;
|
|
using ::ndk::SharedRefBase;
|
|
using ::testing::_;
|
|
using ::testing::AnyNumber;
|
|
using ::testing::AtLeast;
|
|
using ::testing::DoAll;
|
|
using ::testing::Return;
|
|
using ::testing::SaveArg;
|
|
|
|
const char kRegistryInterfaceName[] = "router";
|
|
int testIx = 0;
|
|
|
|
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 = std::string(in_packet.data.begin(), in_packet.data.end());
|
|
timestamp = in_packet.sourceTimeStampMillis;
|
|
return ScopedAStatus::ok();
|
|
}
|
|
std::string data;
|
|
uint64_t timestamp;
|
|
};
|
|
|
|
class ClientInfo : public BnClientInfo {
|
|
public:
|
|
ScopedAStatus getClientName(std::string* _aidl_return) {
|
|
if (_aidl_return) {
|
|
*_aidl_return = "ClientInfo";
|
|
return ScopedAStatus::ok();
|
|
}
|
|
return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
|
|
}
|
|
};
|
|
|
|
class ClientInterface : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
const std::string graphName = "graph " + std::to_string(++testIx);
|
|
proto::Options options;
|
|
options.set_graph_name(graphName);
|
|
mAidlClient = std::make_unique<AidlClient>(options, mEngine);
|
|
|
|
// Register the instance with router.
|
|
EXPECT_EQ(mAidlClient->activate(), 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());
|
|
}
|
|
|
|
std::shared_ptr<tests::MockEngine> mEngine = std::make_unique<tests::MockEngine>();
|
|
std::shared_ptr<AidlClient> mAidlClient = nullptr;
|
|
std::shared_ptr<IPipeRunner> mPipeRunner = nullptr;
|
|
};
|
|
|
|
TEST_F(ClientInterface, TestSetConfiguration) {
|
|
proto::ConfigurationCommand command;
|
|
|
|
// Configure runner to return success.
|
|
EXPECT_CALL(*mEngine, processClientConfigUpdate(_))
|
|
.Times(AtLeast(4))
|
|
.WillRepeatedly(DoAll(SaveArg<0>(&command), Return(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(command.has_set_input_source(), true);
|
|
EXPECT_EQ(command.set_input_source().source_id(), 1);
|
|
|
|
// Test that set offload option returns ok status.
|
|
EXPECT_TRUE(mPipeRunner->setPipeOffloadOptions(5).isOk());
|
|
EXPECT_EQ(command.has_set_offload_offload(), true);
|
|
EXPECT_EQ(command.set_offload_offload().offload_option_id(), 5);
|
|
|
|
// Test that set termination option returns ok status.
|
|
EXPECT_TRUE(mPipeRunner->setPipeTermination(3).isOk());
|
|
EXPECT_EQ(command.has_set_termination_option(), true);
|
|
EXPECT_EQ(command.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(command.has_set_output_stream(), true);
|
|
EXPECT_EQ(command.set_output_stream().stream_id(), 0);
|
|
EXPECT_EQ(command.set_output_stream().max_inflight_packets_count(), 10);
|
|
|
|
// Release runner here. This should remove registry entry from router registry.
|
|
mAidlClient.reset();
|
|
}
|
|
|
|
TEST_F(ClientInterface, TestSetConfigurationError) {
|
|
proto::ConfigurationCommand command;
|
|
|
|
// Configure runner to return error.
|
|
EXPECT_CALL(*mEngine, processClientConfigUpdate(_))
|
|
.Times(AtLeast(4))
|
|
.WillRepeatedly(DoAll(SaveArg<0>(&command), Return(Status::INTERNAL_ERROR)));
|
|
|
|
ScopedAStatus status;
|
|
|
|
// 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(command.has_set_input_source(), true);
|
|
EXPECT_EQ(command.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(command.has_set_offload_offload(), true);
|
|
EXPECT_EQ(command.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(command.has_set_termination_option(), true);
|
|
EXPECT_EQ(command.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(command.has_set_output_stream(), true);
|
|
EXPECT_EQ(command.set_output_stream().stream_id(), 0);
|
|
EXPECT_EQ(command.set_output_stream().max_inflight_packets_count(), 10);
|
|
|
|
// Release runner here. This should remove registry entry from router registry.
|
|
mAidlClient.reset();
|
|
}
|
|
|
|
TEST_F(ClientInterface, TestControlCommands) {
|
|
proto::ControlCommand command;
|
|
// Configure runner to return success.
|
|
EXPECT_CALL(*mEngine, processClientCommand(_))
|
|
.Times(AtLeast(4))
|
|
.WillRepeatedly(DoAll(SaveArg<0>(&command), Return(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(command.has_apply_configs(), true);
|
|
|
|
// Test that set stop graph api returns ok status.
|
|
EXPECT_TRUE(mPipeRunner->resetPipeConfigs().isOk());
|
|
EXPECT_EQ(command.has_reset_configs(), true);
|
|
|
|
// Test that set start graph api returns ok status.
|
|
EXPECT_TRUE(mPipeRunner->startPipe().isOk());
|
|
EXPECT_EQ(command.has_start_graph(), true);
|
|
|
|
// Test that set stop graph api returns ok status.
|
|
EXPECT_TRUE(mPipeRunner->stopPipe().isOk());
|
|
EXPECT_EQ(command.has_stop_graph(), true);
|
|
|
|
// Release runner here. This should remove registry entry from router registry.
|
|
mAidlClient.reset();
|
|
}
|
|
|
|
TEST_F(ClientInterface, TestControlCommandsFailure) {
|
|
proto::ControlCommand command;
|
|
|
|
// Configure runner to return success.
|
|
EXPECT_CALL(*mEngine, processClientCommand(_))
|
|
.Times(AtLeast(4))
|
|
.WillRepeatedly(DoAll(SaveArg<0>(&command), Return(Status::INTERNAL_ERROR)));
|
|
ScopedAStatus status;
|
|
|
|
// 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(command.has_apply_configs(), true);
|
|
|
|
status = mPipeRunner->resetPipeConfigs();
|
|
EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
|
|
EXPECT_EQ(command.has_reset_configs(), true);
|
|
|
|
// Test that start graph api returns error status.
|
|
status = mPipeRunner->startPipe();
|
|
EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
|
|
EXPECT_EQ(command.has_start_graph(), true);
|
|
|
|
// Test that stop graph api returns error status.
|
|
status = mPipeRunner->stopPipe();
|
|
EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
|
|
EXPECT_EQ(command.has_stop_graph(), true);
|
|
|
|
// Release runner here. This should remove registry entry from router registry.
|
|
mAidlClient.reset();
|
|
}
|
|
|
|
TEST_F(ClientInterface, TestFailureWithoutInit) {
|
|
EXPECT_CALL(*mEngine, processClientConfigUpdate(_)).Times(0);
|
|
EXPECT_CALL(*mEngine, processClientCommand(_)).Times(0);
|
|
|
|
// 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);
|
|
|
|
// Test that a control command returns error status.
|
|
status = mPipeRunner->applyPipeConfigs();
|
|
EXPECT_EQ(status.getExceptionCode(), EX_ILLEGAL_STATE);
|
|
}
|
|
|
|
TEST_F(ClientInterface, TestStateChangeNotification) {
|
|
EXPECT_CALL(*mEngine, processClientConfigUpdate(_)).Times(0);
|
|
EXPECT_CALL(*mEngine, processClientCommand(_)).Times(0);
|
|
|
|
// Initialize pipe runner.
|
|
std::shared_ptr<StateChangeCallback> stateCallback =
|
|
ndk::SharedRefBase::make<StateChangeCallback>();
|
|
EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
|
|
|
|
// Test that config complete status is conveyed to client.
|
|
std::map<int, int> m;
|
|
ClientConfig config(0, 0, 0, m, proto::ProfilingType::DISABLED);
|
|
config.setPhaseState(TRANSITION_COMPLETE);
|
|
EXPECT_EQ(mAidlClient->handleConfigPhase(config), Status::SUCCESS);
|
|
EXPECT_EQ(stateCallback->mState, PipeState::CONFIG_DONE);
|
|
|
|
MockRunnerEvent event;
|
|
EXPECT_CALL(event, isTransitionComplete()).Times(AnyNumber()).WillRepeatedly(Return(true));
|
|
EXPECT_CALL(event, isPhaseEntry()).Times(AnyNumber()).WillRepeatedly(Return(false));
|
|
|
|
// Test that reset status is conveyed to client.
|
|
EXPECT_EQ(mAidlClient->handleResetPhase(event), Status::SUCCESS);
|
|
EXPECT_EQ(stateCallback->mState, PipeState::RESET);
|
|
|
|
// Test that execution start status is conveyed to client.
|
|
EXPECT_EQ(mAidlClient->handleExecutionPhase(event), Status::SUCCESS);
|
|
EXPECT_EQ(stateCallback->mState, PipeState::RUNNING);
|
|
|
|
// Test that execution complete status is conveyed to client.
|
|
EXPECT_EQ(mAidlClient->handleStopWithFlushPhase(event), Status::SUCCESS);
|
|
EXPECT_EQ(stateCallback->mState, PipeState::DONE);
|
|
|
|
// Test that execution error status is conveyed to client.
|
|
EXPECT_EQ(mAidlClient->handleStopImmediatePhase(event), Status::SUCCESS);
|
|
EXPECT_EQ(stateCallback->mState, PipeState::ERR_HALT);
|
|
}
|
|
|
|
TEST_F(ClientInterface, TestStateChangeToError) {
|
|
EXPECT_CALL(*mEngine, processClientConfigUpdate(_)).Times(0);
|
|
EXPECT_CALL(*mEngine, processClientCommand(_)).Times(0);
|
|
|
|
// Initialize pipe runner.
|
|
std::shared_ptr<StateChangeCallback> stateCallback =
|
|
ndk::SharedRefBase::make<StateChangeCallback>();
|
|
EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
|
|
|
|
// Test that error while applying config is conveyed to client.
|
|
std::map<int, int> m;
|
|
ClientConfig config(0, 0, 0, m, proto::ProfilingType::DISABLED);
|
|
config.setPhaseState(ABORTED);
|
|
EXPECT_EQ(mAidlClient->handleConfigPhase(config), Status::SUCCESS);
|
|
EXPECT_EQ(stateCallback->mState, PipeState::ERR_HALT);
|
|
|
|
MockRunnerEvent event;
|
|
EXPECT_CALL(event, isTransitionComplete()).Times(AnyNumber()).WillRepeatedly(Return(false));
|
|
EXPECT_CALL(event, isPhaseEntry()).Times(AnyNumber()).WillRepeatedly(Return(false));
|
|
EXPECT_CALL(event, isAborted()).Times(AnyNumber()).WillRepeatedly(Return(true));
|
|
|
|
// Test that error while starting pipe execution is conveyed to client.
|
|
EXPECT_EQ(mAidlClient->handleExecutionPhase(event), Status::SUCCESS);
|
|
EXPECT_EQ(stateCallback->mState, PipeState::ERR_HALT);
|
|
}
|
|
|
|
TEST_F(ClientInterface, TestPacketDelivery) {
|
|
proto::ConfigurationCommand command;
|
|
|
|
// Configure runner to return success.
|
|
EXPECT_CALL(*mEngine, processClientConfigUpdate(_))
|
|
.Times(1)
|
|
.WillOnce(DoAll(SaveArg<0>(&command), Return(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(command.has_set_output_stream(), true);
|
|
EXPECT_EQ(command.set_output_stream().stream_id(), 0);
|
|
EXPECT_EQ(command.set_output_stream().max_inflight_packets_count(), 10);
|
|
|
|
// Send a packet to client and verify the packet.
|
|
std::shared_ptr<MockMemHandle> packet = std::make_unique<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(
|
|
mAidlClient->dispatchPacketToClient(0, static_cast<std::shared_ptr<MemHandle>>(packet)),
|
|
Status::SUCCESS);
|
|
EXPECT_EQ(streamCb->data, packet->getData());
|
|
EXPECT_EQ(streamCb->timestamp, packet->getTimeStamp());
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace aidl_client
|
|
} // namespace client_interface
|
|
} // namespace runner
|
|
} // namespace computepipe
|
|
} // namespace automotive
|
|
} // namespace android
|