From 3729b0bd6074edccb00976690f22a3c7572d652d Mon Sep 17 00:00:00 2001 From: Weilin Xu Date: Wed, 21 Jun 2023 22:49:04 +0000 Subject: [PATCH] Fix wrong timeout and mock method in radio VTS Fixed wrong time unit convension for timeout values used in broadcast radio HAL VTS. Also replaced tuner callback mock method which caused segmentation fault when unimplemented callback methods are called. In addition, antenna connection state was checked at the end of the each test instead of at the beginning. Bug: 277531858 Test: atest VtsHalBroadcastradioAidlTargetTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4420c1dbbf28cc80ac47cdbafb9cc81034f8fc8f) Merged-In: Ied70fcfd2742ae5d253aec984e2161afa6f65162 Change-Id: Ied70fcfd2742ae5d253aec984e2161afa6f65162 --- .../VtsHalBroadcastradioAidlTargetTest.cpp | 219 +++++++++++++----- 1 file changed, 156 insertions(+), 63 deletions(-) diff --git a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp index 356673f715..8bee1b2d1f 100644 --- a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp +++ b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp @@ -32,11 +32,11 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -61,11 +61,6 @@ using ::testing::SaveArg; namespace bcutils = ::aidl::android::hardware::broadcastradio::utils; -inline constexpr std::chrono::seconds kTuneTimeoutSec = - std::chrono::seconds(IBroadcastRadio::TUNER_TIMEOUT_MS * 1000); -inline constexpr std::chrono::seconds kProgramListScanTimeoutSec = - std::chrono::seconds(IBroadcastRadio::LIST_COMPLETE_TIMEOUT_MS * 1000); - const ConfigFlag kConfigFlagValues[] = { ConfigFlag::FORCE_MONO, ConfigFlag::FORCE_ANALOG, @@ -108,20 +103,68 @@ bool supportsFM(const AmFmRegionConfig& config) { } // namespace -class TunerCallbackMock : public BnTunerCallback { +class CallbackFlag final { public: - TunerCallbackMock(); + CallbackFlag(int timeoutMs) { mTimeoutMs = timeoutMs; } + /** + * Notify that the callback is called. + */ + void notify() { + std::unique_lock lock(mMutex); + mCalled = true; + lock.unlock(); + mCv.notify_all(); + }; + + /** + * Wait for the timeout passed into the constructor. + */ + bool wait() { + std::unique_lock lock(mMutex); + return mCv.wait_for(lock, std::chrono::milliseconds(mTimeoutMs), + [this] { return mCalled; }); + }; + + /** + * Reset the callback to not called. + */ + void reset() { + std::unique_lock lock(mMutex); + mCalled = false; + } + + private: + std::mutex mMutex; + bool mCalled GUARDED_BY(mMutex) = false; + std::condition_variable mCv; + int mTimeoutMs; +}; + +class TunerCallbackImpl final : public BnTunerCallback { + public: + TunerCallbackImpl(); ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override; - MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChangedMock, ScopedAStatus(const ProgramInfo&)); ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override; ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override; - MOCK_METHOD1(onAntennaStateChange, ScopedAStatus(bool connected)); - MOCK_METHOD1(onParametersUpdated, ScopedAStatus(const vector& parameters)); - MOCK_METHOD2(onConfigFlagUpdated, ScopedAStatus(ConfigFlag in_flag, bool in_value)); - MOCK_TIMEOUT_METHOD0(onProgramListReady, void()); + ScopedAStatus onParametersUpdated(const vector& parameters) override; + ScopedAStatus onAntennaStateChange(bool connected) override; + ScopedAStatus onConfigFlagUpdated(ConfigFlag in_flag, bool in_value) override; + bool waitOnCurrentProgramInfoChangedCallback(); + bool waitProgramReady(); + void reset(); + + bool getAntennaConnectionState(); + ProgramInfo getCurrentProgramInfo(); + bcutils::ProgramInfoSet getProgramList(); + + private: std::mutex mLock; + bool mAntennaConnectionState GUARDED_BY(mLock); + ProgramInfo mCurrentProgramInfo GUARDED_BY(mLock); bcutils::ProgramInfoSet mProgramList GUARDED_BY(mLock); + CallbackFlag mOnCurrentProgramInfoChangedFlag = CallbackFlag(IBroadcastRadio::TUNER_TIMEOUT_MS); + CallbackFlag mOnProgramListReadyFlag = CallbackFlag(IBroadcastRadio::LIST_COMPLETE_TIMEOUT_MS); }; struct AnnouncementListenerMock : public BnAnnouncementListener { @@ -139,7 +182,7 @@ class BroadcastRadioHalTest : public testing::TestWithParam { std::shared_ptr mModule; Properties mProperties; - std::shared_ptr mCallback = SharedRefBase::make(); + std::shared_ptr mCallback; }; MATCHER_P(InfoHasId, id, string(negation ? "does not contain" : "contains") + " " + id.toString()) { @@ -147,20 +190,18 @@ MATCHER_P(InfoHasId, id, string(negation ? "does not contain" : "contains") + " return ids.end() != find(ids.begin(), ids.end(), id.value); } -TunerCallbackMock::TunerCallbackMock() { - EXPECT_TIMEOUT_CALL(*this, onCurrentProgramInfoChangedMock, _).Times(AnyNumber()); - - // we expect the antenna is connected through the whole test - EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0); +TunerCallbackImpl::TunerCallbackImpl() { + mAntennaConnectionState = true; } -ScopedAStatus TunerCallbackMock::onTuneFailed(Result result, const ProgramSelector& selector) { +ScopedAStatus TunerCallbackImpl::onTuneFailed(Result result, const ProgramSelector& selector) { LOG(DEBUG) << "Tune failed for selector" << selector.toString(); EXPECT_TRUE(result == Result::CANCELED); return ndk::ScopedAStatus::ok(); } -ScopedAStatus TunerCallbackMock::onCurrentProgramInfoChanged(const ProgramInfo& info) { +ScopedAStatus TunerCallbackImpl::onCurrentProgramInfoChanged(const ProgramInfo& info) { + LOG(DEBUG) << "onCurrentProgramInfoChanged called"; for (const auto& id : info.selector) { EXPECT_NE(id.type, IdentifierType::INVALID); } @@ -196,21 +237,75 @@ ScopedAStatus TunerCallbackMock::onCurrentProgramInfoChanged(const ProgramInfo& } } - return onCurrentProgramInfoChangedMock(info); + { + std::lock_guard lk(mLock); + mCurrentProgramInfo = info; + } + + mOnCurrentProgramInfoChangedFlag.notify(); + return ndk::ScopedAStatus::ok(); } -ScopedAStatus TunerCallbackMock::onProgramListUpdated(const ProgramListChunk& chunk) { - std::lock_guard lk(mLock); - - updateProgramList(chunk, &mProgramList); +ScopedAStatus TunerCallbackImpl::onProgramListUpdated(const ProgramListChunk& chunk) { + LOG(DEBUG) << "onProgramListUpdated called"; + { + std::lock_guard lk(mLock); + updateProgramList(chunk, &mProgramList); + } if (chunk.complete) { - onProgramListReady(); + mOnProgramListReadyFlag.notify(); } return ndk::ScopedAStatus::ok(); } +ScopedAStatus TunerCallbackImpl::onParametersUpdated( + [[maybe_unused]] const vector& parameters) { + return ndk::ScopedAStatus::ok(); +} + +ScopedAStatus TunerCallbackImpl::onAntennaStateChange(bool connected) { + if (!connected) { + std::lock_guard lk(mLock); + mAntennaConnectionState = false; + } + return ndk::ScopedAStatus::ok(); +} + +ScopedAStatus TunerCallbackImpl::onConfigFlagUpdated([[maybe_unused]] ConfigFlag in_flag, + [[maybe_unused]] bool in_value) { + return ndk::ScopedAStatus::ok(); +} + +bool TunerCallbackImpl::waitOnCurrentProgramInfoChangedCallback() { + return mOnCurrentProgramInfoChangedFlag.wait(); +} + +bool TunerCallbackImpl::waitProgramReady() { + return mOnProgramListReadyFlag.wait(); +} + +void TunerCallbackImpl::reset() { + mOnCurrentProgramInfoChangedFlag.reset(); + mOnProgramListReadyFlag.reset(); +} + +bool TunerCallbackImpl::getAntennaConnectionState() { + std::lock_guard lk(mLock); + return mAntennaConnectionState; +} + +ProgramInfo TunerCallbackImpl::getCurrentProgramInfo() { + std::lock_guard lk(mLock); + return mCurrentProgramInfo; +} + +bcutils::ProgramInfoSet TunerCallbackImpl::getProgramList() { + std::lock_guard lk(mLock); + return mProgramList; +} + void BroadcastRadioHalTest::SetUp() { EXPECT_EQ(mModule.get(), nullptr) << "Module is already open"; @@ -228,6 +323,8 @@ void BroadcastRadioHalTest::SetUp() { EXPECT_FALSE(mProperties.product.empty()); EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u); + mCallback = SharedRefBase::make(); + // set callback EXPECT_TRUE(mModule->setTunerCallback(mCallback).isOk()); } @@ -236,6 +333,11 @@ void BroadcastRadioHalTest::TearDown() { if (mModule) { ASSERT_TRUE(mModule->unsetTunerCallback().isOk()); } + if (mCallback) { + // we expect the antenna is connected through the whole test + EXPECT_TRUE(mCallback->getAntennaConnectionState()); + mCallback = nullptr; + } } bool BroadcastRadioHalTest::getAmFmRegionConfig(bool full, AmFmRegionConfig* config) { @@ -256,7 +358,7 @@ std::optional BroadcastRadioHalTest::getProgramList() { std::optional BroadcastRadioHalTest::getProgramList( const ProgramFilter& filter) { - EXPECT_TIMEOUT_CALL(*mCallback, onProgramListReady).Times(AnyNumber()); + mCallback->reset(); auto startResult = mModule->startProgramListUpdates(filter); @@ -268,13 +370,13 @@ std::optional BroadcastRadioHalTest::getProgramList( if (!startResult.isOk()) { return std::nullopt; } - EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onProgramListReady, kProgramListScanTimeoutSec); + EXPECT_TRUE(mCallback->waitProgramReady()); auto stopResult = mModule->stopProgramListUpdates(); EXPECT_TRUE(stopResult.isOk()); - return mCallback->mProgramList; + return mCallback->getProgramList(); } /** @@ -456,7 +558,7 @@ TEST_P(BroadcastRadioHalTest, TuneFailsWithoutTunerCallback) { * - if it is supported, the test is ignored; */ TEST_P(BroadcastRadioHalTest, TuneFailsWithNotSupported) { - LOG(DEBUG) << "TuneFailsWithInvalid Test"; + LOG(DEBUG) << "TuneFailsWithNotSupported Test"; vector supportTestId = { makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0), // invalid @@ -477,9 +579,9 @@ TEST_P(BroadcastRadioHalTest, TuneFailsWithNotSupported) { for (const auto& id : supportTestId) { ProgramSelector sel{id, {}}; - auto result = mModule->tune(sel); - if (!bcutils::isSupported(mProperties, sel)) { + auto result = mModule->tune(sel); + EXPECT_EQ(result.getServiceSpecificError(), notSupportedError); } } @@ -508,9 +610,9 @@ TEST_P(BroadcastRadioHalTest, TuneFailsWithInvalid) { for (const auto& id : invalidId) { ProgramSelector sel{id, {}}; - auto result = mModule->tune(sel); - if (bcutils::isSupported(mProperties, sel)) { + auto result = mModule->tune(sel); + EXPECT_EQ(result.getServiceSpecificError(), invalidArgumentsError); } } @@ -549,13 +651,7 @@ TEST_P(BroadcastRadioHalTest, FmTune) { int64_t freq = 90900; // 90.9 FM ProgramSelector sel = makeSelectorAmfm(freq); // try tuning - ProgramInfo infoCb = {}; - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, - InfoHasId(makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, freq))) - .Times(AnyNumber()) - .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(ndk::ScopedAStatus::ok())))) - .WillRepeatedly(testing::InvokeWithoutArgs([] { return ndk::ScopedAStatus::ok(); })); - + mCallback->reset(); auto result = mModule->tune(sel); // expect a failure if it's not supported @@ -566,7 +662,8 @@ TEST_P(BroadcastRadioHalTest, FmTune) { // expect a callback if it succeeds EXPECT_TRUE(result.isOk()); - EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec); + EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback()); + ProgramInfo infoCb = mCallback->getCurrentProgramInfo(); LOG(DEBUG) << "Current program info: " << infoCb.toString(); @@ -638,12 +735,6 @@ TEST_P(BroadcastRadioHalTest, DabTune) { } // try tuning - ProgramInfo infoCb = {}; - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, - InfoHasId(makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq))) - .Times(AnyNumber()) - .WillOnce( - DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(ndk::ScopedAStatus::ok())))); auto result = mModule->tune(sel); @@ -655,7 +746,9 @@ TEST_P(BroadcastRadioHalTest, DabTune) { // expect a callback if it succeeds EXPECT_TRUE(result.isOk()); - EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec); + EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback()); + ProgramInfo infoCb = mCallback->getCurrentProgramInfo(); + LOG(DEBUG) << "Current program info: " << infoCb.toString(); // it should tune exactly to what was requested @@ -669,13 +762,13 @@ TEST_P(BroadcastRadioHalTest, DabTune) { * * Verifies that: * - the method succeeds; - * - the program info is changed within kTuneTimeoutSec; + * - the program info is changed within kTuneTimeoutMs; * - works both directions and with or without skipping sub-channel. */ TEST_P(BroadcastRadioHalTest, Seek) { LOG(DEBUG) << "Seek Test"; - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber()); + mCallback->reset(); auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true); @@ -685,14 +778,14 @@ TEST_P(BroadcastRadioHalTest, Seek) { } EXPECT_TRUE(result.isOk()); - EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec); + EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback()); - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber()); + mCallback->reset(); result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false); EXPECT_TRUE(result.isOk()); - EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec); + EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback()); } /** @@ -720,13 +813,13 @@ TEST_P(BroadcastRadioHalTest, SeekFailsWithoutTunerCallback) { * * Verifies that: * - the method succeeds or returns NOT_SUPPORTED; - * - the program info is changed within kTuneTimeoutSec if the method succeeded; + * - the program info is changed within kTuneTimeoutMs if the method succeeded; * - works both directions. */ TEST_P(BroadcastRadioHalTest, Step) { LOG(DEBUG) << "Step Test"; - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber()); + mCallback->reset(); auto result = mModule->step(/* in_directionUp= */ true); @@ -735,14 +828,14 @@ TEST_P(BroadcastRadioHalTest, Step) { return; } EXPECT_TRUE(result.isOk()); - EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec); + EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback()); - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber()); + mCallback->reset(); result = mModule->step(/* in_directionUp= */ false); EXPECT_TRUE(result.isOk()); - EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec); + EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback()); } /** @@ -955,7 +1048,7 @@ TEST_P(BroadcastRadioHalTest, SetConfigFlags) { * * Verifies that: * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED; - * - the complete list is fetched within kProgramListScanTimeoutSec; + * - the complete list is fetched within kProgramListScanTimeoutMs; * - stopProgramListUpdates does not crash. */ TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) { @@ -969,7 +1062,7 @@ TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) { * * Verifies that: * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED; - * - the complete list is fetched within kProgramListScanTimeoutSec; + * - the complete list is fetched within kProgramListScanTimeoutMs; * - stopProgramListUpdates does not crash; * - result for startProgramListUpdates using a filter with AMFM_FREQUENCY_KHZ value of the first * AMFM program matches the expected result. @@ -1017,7 +1110,7 @@ TEST_P(BroadcastRadioHalTest, GetProgramListFromAmFmFilter) { * * Verifies that: * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED; - * - the complete list is fetched within kProgramListScanTimeoutSec; + * - the complete list is fetched within kProgramListScanTimeoutMs; * - stopProgramListUpdates does not crash; * - result for startProgramListUpdates using a filter with DAB_ENSEMBLE value of the first DAB * program matches the expected result.