Merge "Fix remaining instrumentation tests."
This commit is contained in:
commit
81ccaed5bd
5 changed files with 91 additions and 11 deletions
|
@ -112,6 +112,12 @@ Return<void> BroadcastRadio::getDabRegionConfig(getDabRegionConfig_cb _hidl_cb)
|
|||
Return<void> BroadcastRadio::openSession(const sp<ITunerCallback>& callback,
|
||||
openSession_cb _hidl_cb) {
|
||||
ALOGV("%s", __func__);
|
||||
|
||||
/* For the needs of default implementation it's fine to instantiate new session object
|
||||
* out of the lock scope. If your implementation needs it, use reentrant lock.
|
||||
*/
|
||||
sp<TunerSession> newSession = new TunerSession(*this, callback);
|
||||
|
||||
lock_guard<mutex> lk(mMut);
|
||||
|
||||
auto oldSession = mSession.promote();
|
||||
|
@ -121,7 +127,6 @@ Return<void> BroadcastRadio::openSession(const sp<ITunerCallback>& callback,
|
|||
mSession = nullptr;
|
||||
}
|
||||
|
||||
sp<TunerSession> newSession = new TunerSession(*this, callback);
|
||||
mSession = newSession;
|
||||
|
||||
_hidl_cb(Result::OK, newSession);
|
||||
|
|
|
@ -50,7 +50,12 @@ static constexpr auto list = 1s;
|
|||
} // namespace delay
|
||||
|
||||
TunerSession::TunerSession(BroadcastRadio& module, const sp<ITunerCallback>& callback)
|
||||
: mCallback(callback), mModule(module) {}
|
||||
: mCallback(callback), mModule(module) {
|
||||
auto&& ranges = module.getAmFmConfig().ranges;
|
||||
if (ranges.size() > 0) {
|
||||
tuneInternalLocked(utils::make_selector_amfm(ranges[0].lowerBound));
|
||||
}
|
||||
}
|
||||
|
||||
// makes ProgramInfo that points to no program
|
||||
static ProgramInfo makeDummyProgramInfo(const ProgramSelector& selector) {
|
||||
|
@ -63,6 +68,8 @@ static ProgramInfo makeDummyProgramInfo(const ProgramSelector& selector) {
|
|||
}
|
||||
|
||||
void TunerSession::tuneInternalLocked(const ProgramSelector& sel) {
|
||||
ALOGV("%s(%s)", __func__, toString(sel).c_str());
|
||||
|
||||
VirtualProgram virtualProgram;
|
||||
ProgramInfo programInfo;
|
||||
if (virtualRadio().getProgram(sel, virtualProgram)) {
|
||||
|
@ -100,6 +107,8 @@ Return<Result> TunerSession::tune(const ProgramSelector& sel) {
|
|||
return Result::INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
cancelLocked();
|
||||
|
||||
mIsTuneCompleted = false;
|
||||
auto task = [this, sel]() {
|
||||
lock_guard<mutex> lk(mMut);
|
||||
|
@ -115,6 +124,8 @@ Return<Result> TunerSession::scan(bool directionUp, bool /* skipSubChannel */) {
|
|||
lock_guard<mutex> lk(mMut);
|
||||
if (mIsClosed) return Result::INVALID_STATE;
|
||||
|
||||
cancelLocked();
|
||||
|
||||
auto list = virtualRadio().getProgramList();
|
||||
|
||||
if (list.empty()) {
|
||||
|
@ -166,13 +177,13 @@ Return<Result> TunerSession::step(bool directionUp) {
|
|||
lock_guard<mutex> lk(mMut);
|
||||
if (mIsClosed) return Result::INVALID_STATE;
|
||||
|
||||
cancelLocked();
|
||||
|
||||
if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY)) {
|
||||
ALOGE("Can't step in anything else than AM/FM");
|
||||
return Result::NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
mIsTuneCompleted = false;
|
||||
|
||||
auto stepTo = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY);
|
||||
auto range = getAmFmRangeLocked();
|
||||
if (!range) {
|
||||
|
@ -188,6 +199,7 @@ Return<Result> TunerSession::step(bool directionUp) {
|
|||
if (stepTo > range->upperBound) stepTo = range->lowerBound;
|
||||
if (stepTo < range->lowerBound) stepTo = range->upperBound;
|
||||
|
||||
mIsTuneCompleted = false;
|
||||
auto task = [this, stepTo]() {
|
||||
ALOGI("Performing step to %s", std::to_string(stepTo).c_str());
|
||||
|
||||
|
@ -200,12 +212,22 @@ Return<Result> TunerSession::step(bool directionUp) {
|
|||
return Result::OK;
|
||||
}
|
||||
|
||||
void TunerSession::cancelLocked() {
|
||||
ALOGV("%s", __func__);
|
||||
|
||||
mThread.cancelAll();
|
||||
if (utils::getType(mCurrentProgram.primaryId) != IdentifierType::INVALID) {
|
||||
mIsTuneCompleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
Return<void> TunerSession::cancel() {
|
||||
ALOGV("%s", __func__);
|
||||
lock_guard<mutex> lk(mMut);
|
||||
if (mIsClosed) return {};
|
||||
|
||||
mThread.cancelAll();
|
||||
cancelLocked();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -281,7 +303,10 @@ Return<void> TunerSession::close() {
|
|||
}
|
||||
|
||||
std::optional<AmFmBandRange> TunerSession::getAmFmRangeLocked() const {
|
||||
if (!mIsTuneCompleted) return {};
|
||||
if (!mIsTuneCompleted) {
|
||||
ALOGW("tune operation in process");
|
||||
return {};
|
||||
}
|
||||
if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY)) return {};
|
||||
|
||||
auto freq = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY);
|
||||
|
|
|
@ -63,6 +63,7 @@ struct TunerSession : public ITunerSession {
|
|||
bool mIsTuneCompleted = false;
|
||||
ProgramSelector mCurrentProgram = {};
|
||||
|
||||
void cancelLocked();
|
||||
void tuneInternalLocked(const ProgramSelector& sel);
|
||||
const VirtualRadio& virtualRadio() const;
|
||||
const BroadcastRadio& module() const;
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
|
||||
#define LOG_TAG "BcRadio.vts"
|
||||
#define LOG_NDEBUG 0
|
||||
#define EGMOCK_VERBOSE 1
|
||||
|
||||
#include <VtsHalHidlTargetTestBase.h>
|
||||
#include <android-base/logging.h>
|
||||
|
@ -113,7 +115,15 @@ static void printSkipped(std::string msg) {
|
|||
std::cout << "[ SKIPPED ] " << msg << std::endl;
|
||||
}
|
||||
|
||||
MATCHER_P(InfoHasId, id,
|
||||
std::string(negation ? "does not contain" : "contains") + " " + toString(id)) {
|
||||
auto ids = utils::getAllIds(arg.selector, utils::getType(id));
|
||||
return ids.end() != find(ids.begin(), ids.end(), id.value);
|
||||
}
|
||||
|
||||
TunerCallbackMock::TunerCallbackMock() {
|
||||
EXPECT_TIMEOUT_CALL(*this, onCurrentProgramInfoChanged, _).Times(AnyNumber());
|
||||
|
||||
// we expect the antenna is connected through the whole test
|
||||
EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0);
|
||||
}
|
||||
|
@ -362,9 +372,19 @@ TEST_F(BroadcastRadioHalTest, FmTune) {
|
|||
uint64_t freq = 100100; // 100.1 FM
|
||||
auto sel = make_selector_amfm(freq);
|
||||
|
||||
/* TODO(b/69958777): there is a race condition between tune() and onCurrentProgramInfoChanged
|
||||
* callback setting infoCb, because egmock cannot distinguish calls with different matchers
|
||||
* (there is one here and one in callback constructor).
|
||||
*
|
||||
* This sleep workaround will fix default implementation, but the real HW tests will still be
|
||||
* flaky. We probably need to implement egmock alternative based on actions.
|
||||
*/
|
||||
std::this_thread::sleep_for(100ms);
|
||||
|
||||
// try tuning
|
||||
ProgramInfo infoCb = {};
|
||||
EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _)
|
||||
EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged,
|
||||
InfoHasId(utils::make_identifier(IdentifierType::AMFM_FREQUENCY, freq)))
|
||||
.Times(AnyNumber())
|
||||
.WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(Void()))));
|
||||
auto result = mSession->tune(sel);
|
||||
|
@ -379,6 +399,8 @@ TEST_F(BroadcastRadioHalTest, FmTune) {
|
|||
EXPECT_EQ(Result::OK, result);
|
||||
EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
|
||||
|
||||
ALOGD("current program info: %s", toString(infoCb).c_str());
|
||||
|
||||
// it should tune exactly to what was requested
|
||||
auto freqs = utils::getAllIds(infoCb.selector, IdentifierType::AMFM_FREQUENCY);
|
||||
EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq));
|
||||
|
@ -442,6 +464,9 @@ TEST_F(BroadcastRadioHalTest, TuneFailsWithEmpty) {
|
|||
TEST_F(BroadcastRadioHalTest, Scan) {
|
||||
ASSERT_TRUE(openSession());
|
||||
|
||||
// TODO(b/69958777): see FmTune workaround
|
||||
std::this_thread::sleep_for(100ms);
|
||||
|
||||
EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _);
|
||||
auto result = mSession->scan(true /* up */, true /* skip subchannel */);
|
||||
EXPECT_EQ(Result::OK, result);
|
||||
|
@ -464,9 +489,15 @@ TEST_F(BroadcastRadioHalTest, Scan) {
|
|||
TEST_F(BroadcastRadioHalTest, Step) {
|
||||
ASSERT_TRUE(openSession());
|
||||
|
||||
// TODO(b/69958777): see FmTune workaround
|
||||
std::this_thread::sleep_for(100ms);
|
||||
|
||||
EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _).Times(AnyNumber());
|
||||
auto result = mSession->step(true /* up */);
|
||||
if (result == Result::NOT_SUPPORTED) return;
|
||||
if (result == Result::NOT_SUPPORTED) {
|
||||
printSkipped("step not supported");
|
||||
return;
|
||||
}
|
||||
EXPECT_EQ(Result::OK, result);
|
||||
EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
|
||||
|
||||
|
|
|
@ -13,12 +13,27 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT
|
||||
#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT
|
||||
#ifndef ANDROID_HARDWARE_BROADCASTRADIO_VTS_MOCK_TIMEOUT
|
||||
#define ANDROID_HARDWARE_BROADCASTRADIO_VTS_MOCK_TIMEOUT
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <thread>
|
||||
|
||||
#ifndef EGMOCK_VERBOSE
|
||||
#define EGMOCK_VERBOSE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Print log message.
|
||||
*
|
||||
* INTERNAL IMPLEMENTATION - don't use in user code.
|
||||
*/
|
||||
#if EGMOCK_VERBOSE
|
||||
#define EGMOCK_LOG_(...) ALOGV("egmock: " __VA_ARGS__)
|
||||
#else
|
||||
#define EGMOCK_LOG_(...)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Common helper objects for gmock timeout extension.
|
||||
*
|
||||
|
@ -61,6 +76,7 @@ inline void EGMockFlippedComma_(std::function<void()> returned, std::function<vo
|
|||
auto invokeMock = [&]() { return egmock_##Method(__VA_ARGS__); }; \
|
||||
auto notify = [&]() { \
|
||||
std::lock_guard<std::mutex> lk(egmock_mut_##Method); \
|
||||
EGMOCK_LOG_(#Method " called"); \
|
||||
egmock_called_##Method = true; \
|
||||
egmock_cond_##Method.notify_all(); \
|
||||
}; \
|
||||
|
@ -105,6 +121,7 @@ inline void EGMockFlippedComma_(std::function<void()> returned, std::function<vo
|
|||
* EXPECT_TIMEOUT_CALL(account, charge, 100, Currency::USD);
|
||||
*/
|
||||
#define EXPECT_TIMEOUT_CALL(obj, Method, ...) \
|
||||
EGMOCK_LOG_(#Method " expected to call"); \
|
||||
(obj).egmock_called_##Method = false; \
|
||||
EXPECT_CALL(obj, egmock_##Method(__VA_ARGS__))
|
||||
|
||||
|
@ -124,6 +141,7 @@ inline void EGMockFlippedComma_(std::function<void()> returned, std::function<vo
|
|||
*/
|
||||
#define EXPECT_TIMEOUT_CALL_WAIT(obj, Method, timeout) \
|
||||
{ \
|
||||
EGMOCK_LOG_("waiting for " #Method " call"); \
|
||||
std::unique_lock<std::mutex> lk((obj).egmock_mut_##Method); \
|
||||
if (!(obj).egmock_called_##Method) { \
|
||||
auto status = (obj).egmock_cond_##Method.wait_for(lk, timeout); \
|
||||
|
@ -131,4 +149,4 @@ inline void EGMockFlippedComma_(std::function<void()> returned, std::function<vo
|
|||
} \
|
||||
}
|
||||
|
||||
#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT
|
||||
#endif // ANDROID_HARDWARE_BROADCASTRADIO_VTS_MOCK_TIMEOUT
|
||||
|
|
Loading…
Reference in a new issue