Improve Tuner VTS: Generate DVR Record Combos

This CL allows the VTS to read a vendor's configuration file, determine
if the given devices could support the DVR Record dataflow, and runs the
integration tests with all valid combinations.

2 functions were added to help drive the testing logic.
  generateRecordCombinations() generates all valid record dataflow
  configurations, and the integration tests call
  generateRecordCombinations() to analyze whether to generate these
  combinations or use the data flow provided by the vendor (if there is
  one).

Additionally, when dynamically configuring DVR_Record, a bug was exposed
in the VTS that came about from recycling the function
recordSingleFilterTest(). When LnbRecord was initialized with a software
frontend, the VTS was looking to the record dataflow's dvr source for
input. If record is not hardcoded by the vendor, the VTS would crash.

To fix this error, an enum class was added as a parameter to
RecordSingleFilterTest() to take into consideration which dataflow
(lnbRecord or record [no Lnb]) was calling the function. New behavior is
defined to take into account both cases. Also, lnbRecord will not be
tested if there are no hardware frontends, as this is not very likely to
be configured by vendors.

Bug: b/182519645

Test: vts-tradefed run vts --module VtsHalTvTunerTargetTest. Manual
tests with different input configuration files.

Change-Id: I76c05ca2e33767e4bdcd2072db5144d495d623b0
This commit is contained in:
Frankie Lizcano 2022-07-18 17:56:52 +00:00
parent 0c0695379d
commit 9c464f7c5c
3 changed files with 122 additions and 30 deletions

View file

@ -260,7 +260,9 @@ void TunerRecordAidlTest::recordSingleFilterTestWithLnb(FilterConfig filterConf,
for (auto msgName : lnbRecord.diseqcMsgs) {
ASSERT_TRUE(mLnbTests.sendDiseqcMessage(diseqcMsgMap[msgName]));
}
recordSingleFilterTest(filterConf, frontendConf, dvrConf);
if (!frontendConf.isSoftwareFe) {
recordSingleFilterTest(filterConf, frontendConf, dvrConf, Dataflow_Context::LNBRECORD);
}
ASSERT_TRUE(mLnbTests.closeLnb());
mLnbId = INVALID_LNB_ID;
}
@ -318,29 +320,47 @@ void TunerRecordAidlTest::attachSingleFilterToRecordDvrTest(FilterConfig filterC
}
void TunerRecordAidlTest::recordSingleFilterTest(FilterConfig filterConf,
FrontendConfig frontendConf, DvrConfig dvrConf) {
FrontendConfig frontendConf, DvrConfig dvrConf,
Dataflow_Context context) {
int32_t demuxId;
std::shared_ptr<IDemux> demux;
ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
mDvrTests.setDemux(demux);
DvrConfig dvrSourceConfig;
if (record.hasFrontendConnection) {
if (context == Dataflow_Context::RECORD) {
if (record.hasFrontendConnection) {
int32_t feId;
mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
ASSERT_TRUE(feId != INVALID_ID);
ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
if (frontendConf.isSoftwareFe) {
mFrontendTests.setSoftwareFrontendDvrConfig(dvrMap[record.dvrSoftwareFeId]);
}
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
mFrontendTests.setDvrTests(&mDvrTests);
} else {
dvrSourceConfig = dvrMap[record.dvrSourceId];
ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrSourceConfig.type, dvrSourceConfig.bufferSize));
ASSERT_TRUE(mDvrTests.configDvrPlayback(dvrSourceConfig.settings));
ASSERT_TRUE(mDvrTests.getDvrPlaybackMQDescriptor());
}
} else if (context == Dataflow_Context::LNBRECORD) {
// If function arrives here, frontend should not be software, so no need to configure a dvr
// source or dvr fe connection that might be used for recording without an Lnb
int32_t feId;
mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
ASSERT_TRUE(feId != INVALID_ID);
ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
if (frontendConf.isSoftwareFe) {
mFrontendTests.setSoftwareFrontendDvrConfig(dvrMap[record.dvrSoftwareFeId]);
if (mLnbId != INVALID_LNB_ID) {
ASSERT_TRUE(mFrontendTests.setLnb(mLnbId));
} else {
FAIL();
}
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
mFrontendTests.setDvrTests(&mDvrTests);
} else {
dvrSourceConfig = dvrMap[record.dvrSourceId];
ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrSourceConfig.type, dvrSourceConfig.bufferSize));
ASSERT_TRUE(mDvrTests.configDvrPlayback(dvrSourceConfig.settings));
ASSERT_TRUE(mDvrTests.getDvrPlaybackMQDescriptor());
}
int64_t filterId;
@ -360,24 +380,31 @@ void TunerRecordAidlTest::recordSingleFilterTest(FilterConfig filterConf,
ASSERT_TRUE(mDvrTests.startDvrRecord());
ASSERT_TRUE(mFilterTests.startFilter(filterId));
if (record.hasFrontendConnection) {
if (context == Dataflow_Context::RECORD) {
if (record.hasFrontendConnection) {
ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
} else {
// Start DVR Source
mDvrTests.startPlaybackInputThread(
dvrSourceConfig.playbackInputFile,
dvrSourceConfig.settings.get<DvrSettings::Tag::playback>());
ASSERT_TRUE(mDvrTests.startDvrPlayback());
}
} else if (context == Dataflow_Context::LNBRECORD) {
ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
} else {
// Start DVR Source
mDvrTests.startPlaybackInputThread(
dvrSourceConfig.playbackInputFile,
dvrSourceConfig.settings.get<DvrSettings::Tag::playback>());
ASSERT_TRUE(mDvrTests.startDvrPlayback());
}
mDvrTests.testRecordOutput();
mDvrTests.stopRecordThread();
if (record.hasFrontendConnection) {
if (context == Dataflow_Context::RECORD) {
if (record.hasFrontendConnection) {
ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
} else {
mDvrTests.stopPlaybackThread();
ASSERT_TRUE(mDvrTests.stopDvrPlayback());
}
} else if (context == Dataflow_Context::LNBRECORD) {
ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
} else {
mDvrTests.stopPlaybackThread();
ASSERT_TRUE(mDvrTests.stopDvrPlayback());
}
ASSERT_TRUE(mFilterTests.stopFilter(filterId));
@ -386,10 +413,14 @@ void TunerRecordAidlTest::recordSingleFilterTest(FilterConfig filterConf,
ASSERT_TRUE(mFilterTests.closeFilter(filterId));
mDvrTests.closeDvrRecord();
if (record.hasFrontendConnection) {
if (context == Dataflow_Context::RECORD) {
if (record.hasFrontendConnection) {
ASSERT_TRUE(mFrontendTests.closeFrontend());
} else {
mDvrTests.closeDvrPlayback();
}
} else if (context == Dataflow_Context::LNBRECORD) {
ASSERT_TRUE(mFrontendTests.closeFrontend());
} else {
mDvrTests.closeDvrPlayback();
}
ASSERT_TRUE(mDemuxTests.closeDemux());
@ -892,8 +923,12 @@ TEST_P(TunerRecordAidlTest, RecordDataFlowWithTsRecordFilterTest) {
if (!record.support) {
return;
}
recordSingleFilterTest(filterMap[record.recordFilterId], frontendMap[record.frontendId],
dvrMap[record.dvrRecordId]);
auto record_configs = generateRecordConfigurations();
for (auto& configuration : record_configs) {
record = configuration;
recordSingleFilterTest(filterMap[record.recordFilterId], frontendMap[record.frontendId],
dvrMap[record.dvrRecordId], Dataflow_Context::RECORD);
}
}
TEST_P(TunerRecordAidlTest, AttachFiltersToRecordTest) {
@ -902,8 +937,13 @@ TEST_P(TunerRecordAidlTest, AttachFiltersToRecordTest) {
if (!record.support) {
return;
}
attachSingleFilterToRecordDvrTest(filterMap[record.recordFilterId],
frontendMap[record.frontendId], dvrMap[record.dvrRecordId]);
auto record_configs = generateRecordConfigurations();
for (auto& configuration : record_configs) {
record = configuration;
attachSingleFilterToRecordDvrTest(filterMap[record.recordFilterId],
frontendMap[record.frontendId],
dvrMap[record.dvrRecordId]);
}
}
TEST_P(TunerRecordAidlTest, LnbRecordDataFlowWithTsRecordFilterTest) {

View file

@ -78,6 +78,8 @@ void clearIds() {
sectionFilterIds.clear();
}
enum class Dataflow_Context { LNBRECORD, RECORD };
class TunerLnbAidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
@ -289,7 +291,7 @@ class TunerRecordAidlTest : public testing::TestWithParam<std::string> {
void recordSingleFilterTestWithLnb(FilterConfig filterConf, FrontendConfig frontendConf,
DvrConfig dvrConf, LnbConfig lnbConf);
void recordSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf,
DvrConfig dvrConf);
DvrConfig dvrConf, Dataflow_Context context);
std::shared_ptr<ITuner> mService;
FrontendTests mFrontendTests;

View file

@ -407,6 +407,56 @@ static inline vector<TimeFilterHardwareConnections> generateTimeFilterConfigurat
return timeFilter_configs;
}
/*
* index 0 - frontends
* index 1 - record dvrs
* index 2 - record filters
*/
static inline vector<DvrRecordHardwareConnections> generateRecordCombinations() {
vector<DvrRecordHardwareConnections> combinations;
const int frontendIdIndex = 0;
const int recordDvrIndex = 1;
const int recordFilterIndex = 2;
vector<vector<string>> deviceIds{frontendIds, recordDvrIds, recordFilterIds};
auto idCombinations = generateIdCombinations(deviceIds);
for (auto& combo : idCombinations) {
DvrRecordHardwareConnections mRecord;
const string feId = combo[frontendIdIndex];
mRecord.hasFrontendConnection = true;
if (frontendMap[feId].isSoftwareFe) {
// If we have a software frontend, do not include configuration for testing.
continue;
}
mRecord.frontendId = feId;
mRecord.support = true;
mRecord.dvrSourceId = emptyHardwareId;
mRecord.dvrSoftwareFeId = emptyHardwareId;
mRecord.recordFilterId = combo[recordFilterIndex];
mRecord.dvrRecordId = combo[recordDvrIndex];
combinations.push_back(mRecord);
}
return combinations;
}
static inline vector<DvrRecordHardwareConnections> generateRecordConfigurations() {
vector<DvrRecordHardwareConnections> record_configs;
if (configuredRecord) {
ALOGD("Using Record configuration provided.");
record_configs = {record};
} else {
ALOGD("Record not provided. Generating possible combinations. Consider adding it to "
"the "
"configuration file.");
record_configs = generateRecordCombinations();
}
return record_configs;
}
/** Config all the frontends that would be used in the tests */
inline void initFrontendConfig() {
// The test will use the internal default fe when default fe is connected to any data flow