Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d8f18469 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix wrong timeout and mock method in radio VTS" into stage-aosp-udc-ts-dev

parents e410f8cc 3729b0bd
Loading
Loading
Loading
Loading
+156 −63
Original line number Diff line number Diff line
@@ -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>

@@ -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:
    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 {
@@ -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()) {
@@ -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<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";

@@ -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());
}
@@ -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<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);

@@ -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();
}

/**
@@ -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
@@ -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);
        }
    }
@@ -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);
        }
    }
@@ -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.