/*
* Copyright (C) 2018 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_NDEBUG 0
#define LOG_TAG "codec2_hidl_hal_component_test"
#include <android-base/logging.h>
#include <gtest/gtest.h>
#include <hardware/google/media/c2/1.0/IComponent.h>
#include <hardware/google/media/c2/1.0/IComponentStore.h>
using ::hardware::google::media::c2::V1_0::IComponent;
using ::hardware::google::media::c2::V1_0::IComponentStore;
using ::hardware::google::media::c2::V1_0::IComponentInterface;
using ::hardware::google::media::c2::V1_0::FieldSupportedValuesQuery;
using ::hardware::google::media::c2::V1_0::FieldSupportedValuesQueryResult;
using ::hardware::google::media::c2::V1_0::ParamDescriptor;
using ::hardware::google::media::c2::V1_0::SettingResult;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
using ::android::sp;
#include <VtsHalHidlTargetTestBase.h>
#include "media_c2_hidl_test_common.h"
static ComponentTestEnvironment* gEnv = nullptr;
namespace {
// google.codec2 Component test setup
class Codec2ComponentHalTest : public ::testing::VtsHalHidlTargetTestBase {
private:
typedef ::testing::VtsHalHidlTargetTestBase Super;
public:
virtual void SetUp() override {
Super::SetUp();
mStore = Super::getService<IComponentStore>(gEnv->getInstance());
ASSERT_NE(mStore, nullptr);
mListener = new CodecListener();
ASSERT_NE(mListener, nullptr);
mStore->createComponent(gEnv->getComponent().c_str(), mListener,
nullptr,
[&](Status _s, const sp<IComponent>& _nl) {
ASSERT_EQ(_s, Status::OK);
this->mComponent = _nl;
});
ASSERT_NE(mComponent, nullptr);
}
virtual void TearDown() override {
if (mComponent != nullptr) {
// If you have encountered a fatal failure, it is possible that
// freeNode() will not go through. Instead of hanging the app.
// let it pass through and report errors
if (::testing::Test::HasFatalFailure()) return;
mComponent->release();
mComponent = nullptr;
}
Super::TearDown();
}
sp<IComponent> mComponent;
sp<IComponentStore> mStore;
sp<CodecListener> mListener;
protected:
static void description(const std::string& description) {
RecordProperty("description", description);
}
};
// Test Empty Flush
TEST_F(Codec2ComponentHalTest, EmptyFlush) {
ALOGV("Empty Flush Test");
Status err = mComponent->start();
ASSERT_EQ(err, Status::OK);
// Flushed output expected to be of 0 size, as no input has been fed
mComponent->flush([&](Status _s, const WorkBundle& _flushedWorkBundle) {
ASSERT_EQ(_s, Status::OK);
ASSERT_EQ(_flushedWorkBundle.works.size(), 0u)
<< "Invalid Flushed Work Size";
ASSERT_EQ(_flushedWorkBundle.baseBlocks.size(), 0u);
});
}
// Test Queue Empty Work
TEST_F(Codec2ComponentHalTest, QueueEmptyWork) {
ALOGV("Queue Empty Work Test");
Status err = mComponent->start();
ASSERT_EQ(err, Status::OK);
// Queueing an empty WorkBundle
const WorkBundle workBundle = {};
err = mComponent->queue(workBundle);
ASSERT_EQ(err, Status::OK);
err = mComponent->reset();
ASSERT_EQ(err, Status::OK);
}
// Test Component Configuration
TEST_F(Codec2ComponentHalTest, Config) {
ALOGV("Configuration Test");
mComponent->getName([](const hidl_string& name) {
EXPECT_NE(name.empty(), true) << "Invalid Component Store Name";
ALOGV("Component under Test %s", name.c_str());
});
#define MAX_PARAMS 64
/* Querry Supported Params */
hidl_vec<ParamDescriptor> params;
mComponent->querySupportedParams(
0, MAX_PARAMS,
[¶ms](Status _s, const hidl_vec<ParamDescriptor>& _p) {
ASSERT_EQ(_s, Status::OK);
params = _p;
ALOGE("TEMP - Params capacity - %zu", _p.size());
});
std::vector<uint32_t> tempIndices;
std::vector<FieldSupportedValuesQuery> tempInFields;
for (size_t i = 0; i < params.size(); i++) {
EXPECT_NE(params[i].name.empty(), true)
<< "Invalid Supported Param Name";
ALOGV("Params Supported : %s", params[i].name.c_str());
tempIndices.push_back(params[i].index);
FieldSupportedValuesQuery tempFSV;
tempFSV.field.index = params[i].index;
tempInFields.push_back(tempFSV);
}
/* Query Supported Values */
const hidl_vec<FieldSupportedValuesQuery> inFields = tempInFields;
bool mayBlock = false;
hidl_vec<FieldSupportedValuesQueryResult> outFields;
mComponent->querySupportedValues(
inFields, mayBlock,
[&outFields](
Status _s,
const hidl_vec<FieldSupportedValuesQueryResult>& _outFields) {
ASSERT_EQ(_s, Status::OK);
outFields = _outFields;
});
// Fileds size should match
ASSERT_EQ(inFields.size(), outFields.size());
/* TODO: How to give proper indices */
const hidl_vec<uint32_t> indices = tempIndices;
hidl_vec<uint8_t> inParamsQuery;
mComponent->query(indices, mayBlock,
[&inParamsQuery](Status _s, const hidl_vec<uint8_t>& _p) {
ASSERT_EQ(_s, Status::OK);
inParamsQuery = _p;
});
/* Config default parameters*/
const hidl_vec<uint8_t> inParams = inParamsQuery;
hidl_vec<uint8_t> outParamsQuery;
mComponent->config(
inParams, mayBlock,
[&outParamsQuery](Status _s, const hidl_vec<SettingResult>& _f,
const hidl_vec<uint8_t>& _outParams) {
ASSERT_EQ(_s, Status::OK);
// There should be no failures, since default config is reapplied
ASSERT_EQ(_f.size(), 0u);
outParamsQuery = _outParams;
});
// Fileds size should match
ASSERT_EQ(inParams.size(), outParamsQuery.size());
}
// Test Multiple Start Stop Reset Test
TEST_F(Codec2ComponentHalTest, MultipleStartStopReset) {
ALOGV("Multiple Start Stop and Reset Test");
Status err = Status::OK;
#define MAX_RETRY 16
for (size_t i = 0; i < MAX_RETRY; i++) {
err = mComponent->start();
ASSERT_EQ(err, Status::OK);
err = mComponent->stop();
ASSERT_EQ(err, Status::OK);
}
err = mComponent->start();
ASSERT_EQ(err, Status::OK);
for (size_t i = 0; i < MAX_RETRY; i++) {
err = mComponent->reset();
ASSERT_EQ(err, Status::OK);
}
err = mComponent->start();
ASSERT_EQ(err, Status::OK);
err = mComponent->stop();
ASSERT_EQ(err, Status::OK);
// Second stop should return error
err = mComponent->stop();
ASSERT_NE(err, Status::OK);
}
} // anonymous namespace
// TODO: Add test for Invalid work, Invalid Config handling
// TODO: Add test for Invalid states
int main(int argc, char** argv) {
gEnv = new ComponentTestEnvironment();
::testing::AddGlobalTestEnvironment(gEnv);
::testing::InitGoogleTest(&argc, argv);
gEnv->init(&argc, argv);
int status = gEnv->initFromOptions(argc, argv);
if (status == 0) {
status = RUN_ALL_TESTS();
LOG(INFO) << "C2 Test result = " << status;
}
return status;
}