Loading broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp +156 −63 Original line number Diff line number Diff line Loading @@ -32,11 +32,11 @@ #include <aidl/Gtest.h> #include <aidl/Vintf.h> #include <broadcastradio-utils-aidl/Utils.h> #include <broadcastradio-vts-utils/mock-timeout.h> #include <cutils/bitops.h> #include <gmock/gmock.h> #include <chrono> #include <condition_variable> #include <optional> #include <regex> Loading @@ -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, Loading Loading @@ -108,20 +103,68 @@ bool supportsFM(const AmFmRegionConfig& config) { } // namespace class TunerCallbackMock : public BnTunerCallback { class CallbackFlag final { public: CallbackFlag(int timeoutMs) { mTimeoutMs = timeoutMs; } /** * Notify that the callback is called. */ void notify() { std::unique_lock<std::mutex> lock(mMutex); mCalled = true; lock.unlock(); mCv.notify_all(); }; /** * Wait for the timeout passed into the constructor. */ bool wait() { std::unique_lock<std::mutex> 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<std::mutex> 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: TunerCallbackMock(); 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<VendorKeyValue>& parameters)); MOCK_METHOD2(onConfigFlagUpdated, ScopedAStatus(ConfigFlag in_flag, bool in_value)); MOCK_TIMEOUT_METHOD0(onProgramListReady, void()); ScopedAStatus onParametersUpdated(const vector<VendorKeyValue>& 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 { Loading @@ -139,7 +182,7 @@ class BroadcastRadioHalTest : public testing::TestWithParam<string> { std::shared_ptr<IBroadcastRadio> mModule; Properties mProperties; std::shared_ptr<TunerCallbackMock> mCallback = SharedRefBase::make<TunerCallbackMock>(); std::shared_ptr<TunerCallbackImpl> mCallback; }; MATCHER_P(InfoHasId, id, string(negation ? "does not contain" : "contains") + " " + id.toString()) { Loading @@ -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); } Loading Loading @@ -196,21 +237,75 @@ ScopedAStatus TunerCallbackMock::onCurrentProgramInfoChanged(const ProgramInfo& } } return onCurrentProgramInfoChangedMock(info); { std::lock_guard<std::mutex> lk(mLock); mCurrentProgramInfo = info; } ScopedAStatus TunerCallbackMock::onProgramListUpdated(const ProgramListChunk& chunk) { std::lock_guard<std::mutex> lk(mLock); mOnCurrentProgramInfoChangedFlag.notify(); return ndk::ScopedAStatus::ok(); } ScopedAStatus TunerCallbackImpl::onProgramListUpdated(const ProgramListChunk& chunk) { LOG(DEBUG) << "onProgramListUpdated called"; { std::lock_guard<std::mutex> lk(mLock); updateProgramList(chunk, &mProgramList); } if (chunk.complete) { onProgramListReady(); mOnProgramListReadyFlag.notify(); } return ndk::ScopedAStatus::ok(); } ScopedAStatus TunerCallbackImpl::onParametersUpdated( [[maybe_unused]] const vector<VendorKeyValue>& parameters) { return ndk::ScopedAStatus::ok(); } ScopedAStatus TunerCallbackImpl::onAntennaStateChange(bool connected) { if (!connected) { std::lock_guard<std::mutex> 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<std::mutex> lk(mLock); return mAntennaConnectionState; } ProgramInfo TunerCallbackImpl::getCurrentProgramInfo() { std::lock_guard<std::mutex> lk(mLock); return mCurrentProgramInfo; } bcutils::ProgramInfoSet TunerCallbackImpl::getProgramList() { std::lock_guard<std::mutex> lk(mLock); return mProgramList; } void BroadcastRadioHalTest::SetUp() { EXPECT_EQ(mModule.get(), nullptr) << "Module is already open"; Loading @@ -228,6 +323,8 @@ void BroadcastRadioHalTest::SetUp() { EXPECT_FALSE(mProperties.product.empty()); EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u); mCallback = SharedRefBase::make<TunerCallbackImpl>(); // set callback EXPECT_TRUE(mModule->setTunerCallback(mCallback).isOk()); } Loading @@ -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) { Loading @@ -256,7 +358,7 @@ std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList() { std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList( const ProgramFilter& filter) { EXPECT_TIMEOUT_CALL(*mCallback, onProgramListReady).Times(AnyNumber()); mCallback->reset(); auto startResult = mModule->startProgramListUpdates(filter); Loading @@ -268,13 +370,13 @@ std::optional<bcutils::ProgramInfoSet> 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(); } /** Loading Loading @@ -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<ProgramIdentifier> supportTestId = { makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0), // invalid Loading @@ -477,9 +579,9 @@ TEST_P(BroadcastRadioHalTest, TuneFailsWithNotSupported) { for (const auto& id : supportTestId) { ProgramSelector sel{id, {}}; if (!bcutils::isSupported(mProperties, sel)) { auto result = mModule->tune(sel); if (!bcutils::isSupported(mProperties, sel)) { EXPECT_EQ(result.getServiceSpecificError(), notSupportedError); } } Loading Loading @@ -508,9 +610,9 @@ TEST_P(BroadcastRadioHalTest, TuneFailsWithInvalid) { for (const auto& id : invalidId) { ProgramSelector sel{id, {}}; if (bcutils::isSupported(mProperties, sel)) { auto result = mModule->tune(sel); if (bcutils::isSupported(mProperties, sel)) { EXPECT_EQ(result.getServiceSpecificError(), invalidArgumentsError); } } Loading Loading @@ -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 Loading @@ -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(); Loading Loading @@ -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); Loading @@ -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 Loading @@ -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); Loading @@ -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()); } /** Loading Loading @@ -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); Loading @@ -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()); } /** Loading Loading @@ -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) { Loading @@ -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. Loading Loading @@ -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. Loading Loading
broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp +156 −63 Original line number Diff line number Diff line Loading @@ -32,11 +32,11 @@ #include <aidl/Gtest.h> #include <aidl/Vintf.h> #include <broadcastradio-utils-aidl/Utils.h> #include <broadcastradio-vts-utils/mock-timeout.h> #include <cutils/bitops.h> #include <gmock/gmock.h> #include <chrono> #include <condition_variable> #include <optional> #include <regex> Loading @@ -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, Loading Loading @@ -108,20 +103,68 @@ bool supportsFM(const AmFmRegionConfig& config) { } // namespace class TunerCallbackMock : public BnTunerCallback { class CallbackFlag final { public: CallbackFlag(int timeoutMs) { mTimeoutMs = timeoutMs; } /** * Notify that the callback is called. */ void notify() { std::unique_lock<std::mutex> lock(mMutex); mCalled = true; lock.unlock(); mCv.notify_all(); }; /** * Wait for the timeout passed into the constructor. */ bool wait() { std::unique_lock<std::mutex> 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<std::mutex> 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: TunerCallbackMock(); 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<VendorKeyValue>& parameters)); MOCK_METHOD2(onConfigFlagUpdated, ScopedAStatus(ConfigFlag in_flag, bool in_value)); MOCK_TIMEOUT_METHOD0(onProgramListReady, void()); ScopedAStatus onParametersUpdated(const vector<VendorKeyValue>& 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 { Loading @@ -139,7 +182,7 @@ class BroadcastRadioHalTest : public testing::TestWithParam<string> { std::shared_ptr<IBroadcastRadio> mModule; Properties mProperties; std::shared_ptr<TunerCallbackMock> mCallback = SharedRefBase::make<TunerCallbackMock>(); std::shared_ptr<TunerCallbackImpl> mCallback; }; MATCHER_P(InfoHasId, id, string(negation ? "does not contain" : "contains") + " " + id.toString()) { Loading @@ -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); } Loading Loading @@ -196,21 +237,75 @@ ScopedAStatus TunerCallbackMock::onCurrentProgramInfoChanged(const ProgramInfo& } } return onCurrentProgramInfoChangedMock(info); { std::lock_guard<std::mutex> lk(mLock); mCurrentProgramInfo = info; } ScopedAStatus TunerCallbackMock::onProgramListUpdated(const ProgramListChunk& chunk) { std::lock_guard<std::mutex> lk(mLock); mOnCurrentProgramInfoChangedFlag.notify(); return ndk::ScopedAStatus::ok(); } ScopedAStatus TunerCallbackImpl::onProgramListUpdated(const ProgramListChunk& chunk) { LOG(DEBUG) << "onProgramListUpdated called"; { std::lock_guard<std::mutex> lk(mLock); updateProgramList(chunk, &mProgramList); } if (chunk.complete) { onProgramListReady(); mOnProgramListReadyFlag.notify(); } return ndk::ScopedAStatus::ok(); } ScopedAStatus TunerCallbackImpl::onParametersUpdated( [[maybe_unused]] const vector<VendorKeyValue>& parameters) { return ndk::ScopedAStatus::ok(); } ScopedAStatus TunerCallbackImpl::onAntennaStateChange(bool connected) { if (!connected) { std::lock_guard<std::mutex> 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<std::mutex> lk(mLock); return mAntennaConnectionState; } ProgramInfo TunerCallbackImpl::getCurrentProgramInfo() { std::lock_guard<std::mutex> lk(mLock); return mCurrentProgramInfo; } bcutils::ProgramInfoSet TunerCallbackImpl::getProgramList() { std::lock_guard<std::mutex> lk(mLock); return mProgramList; } void BroadcastRadioHalTest::SetUp() { EXPECT_EQ(mModule.get(), nullptr) << "Module is already open"; Loading @@ -228,6 +323,8 @@ void BroadcastRadioHalTest::SetUp() { EXPECT_FALSE(mProperties.product.empty()); EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u); mCallback = SharedRefBase::make<TunerCallbackImpl>(); // set callback EXPECT_TRUE(mModule->setTunerCallback(mCallback).isOk()); } Loading @@ -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) { Loading @@ -256,7 +358,7 @@ std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList() { std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList( const ProgramFilter& filter) { EXPECT_TIMEOUT_CALL(*mCallback, onProgramListReady).Times(AnyNumber()); mCallback->reset(); auto startResult = mModule->startProgramListUpdates(filter); Loading @@ -268,13 +370,13 @@ std::optional<bcutils::ProgramInfoSet> 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(); } /** Loading Loading @@ -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<ProgramIdentifier> supportTestId = { makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0), // invalid Loading @@ -477,9 +579,9 @@ TEST_P(BroadcastRadioHalTest, TuneFailsWithNotSupported) { for (const auto& id : supportTestId) { ProgramSelector sel{id, {}}; if (!bcutils::isSupported(mProperties, sel)) { auto result = mModule->tune(sel); if (!bcutils::isSupported(mProperties, sel)) { EXPECT_EQ(result.getServiceSpecificError(), notSupportedError); } } Loading Loading @@ -508,9 +610,9 @@ TEST_P(BroadcastRadioHalTest, TuneFailsWithInvalid) { for (const auto& id : invalidId) { ProgramSelector sel{id, {}}; if (bcutils::isSupported(mProperties, sel)) { auto result = mModule->tune(sel); if (bcutils::isSupported(mProperties, sel)) { EXPECT_EQ(result.getServiceSpecificError(), invalidArgumentsError); } } Loading Loading @@ -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 Loading @@ -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(); Loading Loading @@ -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); Loading @@ -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 Loading @@ -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); Loading @@ -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()); } /** Loading Loading @@ -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); Loading @@ -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()); } /** Loading Loading @@ -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) { Loading @@ -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. Loading Loading @@ -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. Loading