Loading broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp +2 −23 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include <broadcastradio-utils-1x/Utils.h> #include <broadcastradio-vts-utils/call-barrier.h> #include <broadcastradio-vts-utils/mock-timeout.h> #include <broadcastradio-vts-utils/pointer-utils.h> #include <cutils/native_handle.h> #include <cutils/properties.h> #include <gmock/gmock.h> Loading Loading @@ -56,8 +57,7 @@ using V1_0::MetaData; using V1_0::MetadataKey; using V1_0::MetadataType; using std::chrono::steady_clock; using std::this_thread::sleep_for; using broadcastradio::vts::clearAndWait; static constexpr auto kConfigTimeout = 10s; static constexpr auto kConnectModuleTimeout = 1s; Loading Loading @@ -115,27 +115,6 @@ class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase, hidl_vec<BandConfig> mBands; }; /** * Clears strong pointer and waits until the object gets destroyed. * * @param ptr The pointer to get cleared. * @param timeout Time to wait for other references. */ template <typename T> static void clearAndWait(sp<T>& ptr, std::chrono::milliseconds timeout) { wp<T> wptr = ptr; ptr.clear(); auto limit = steady_clock::now() + timeout; while (wptr.promote() != nullptr) { constexpr auto step = 10ms; if (steady_clock::now() + step > limit) { FAIL() << "Pointer was not released within timeout"; break; } sleep_for(step); } } void BroadcastRadioHalTest::SetUp() { radioClass = GetParam(); Loading broadcastradio/1.2/vts/functional/VtsHalBroadcastradioV1_2TargetTest.cpp +3 −24 Original line number Diff line number Diff line Loading @@ -17,14 +17,15 @@ #define LOG_TAG "broadcastradio.vts" #include <VtsHalHidlTargetTestBase.h> #include <android-base/logging.h> #include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h> #include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h> #include <android/hardware/broadcastradio/1.2/ITuner.h> #include <android/hardware/broadcastradio/1.2/ITunerCallback.h> #include <android/hardware/broadcastradio/1.2/types.h> #include <android-base/logging.h> #include <broadcastradio-vts-utils/call-barrier.h> #include <broadcastradio-vts-utils/mock-timeout.h> #include <broadcastradio-vts-utils/pointer-utils.h> #include <cutils/native_handle.h> #include <cutils/properties.h> #include <gmock/gmock.h> Loading Loading @@ -60,8 +61,7 @@ using V1_1::ProgramListResult; using V1_1::ProgramSelector; using V1_1::Properties; using std::chrono::steady_clock; using std::this_thread::sleep_for; using broadcastradio::vts::clearAndWait; static constexpr auto kConfigTimeout = 10s; static constexpr auto kConnectModuleTimeout = 1s; Loading Loading @@ -110,27 +110,6 @@ class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase, hidl_vec<BandConfig> mBands; }; /** * Clears strong pointer and waits until the object gets destroyed. * * @param ptr The pointer to get cleared. * @param timeout Time to wait for other references. */ template <typename T> static void clearAndWait(sp<T>& ptr, std::chrono::milliseconds timeout) { wp<T> wptr = ptr; ptr.clear(); auto limit = steady_clock::now() + timeout; while (wptr.promote() != nullptr) { constexpr auto step = 10ms; if (steady_clock::now() + step > limit) { FAIL() << "Pointer was not released within timeout"; break; } sleep_for(step); } } void BroadcastRadioHalTest::SetUp() { radioClass = GetParam(); Loading broadcastradio/2.0/vts/OWNERS 0 → 100644 +7 −0 Original line number Diff line number Diff line # Automotive team egranata@google.com twasilczyk@google.com # VTS team yuexima@google.com yim@google.com broadcastradio/2.0/vts/functional/Android.bp 0 → 100644 +28 −0 Original line number Diff line number Diff line // // Copyright (C) 2017 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // cc_test { name: "VtsHalBroadcastradioV2_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalBroadcastradioV2_0TargetTest.cpp"], static_libs: [ "android.hardware.broadcastradio@2.0", "android.hardware.broadcastradio@common-utils-2x-lib", "android.hardware.broadcastradio@vts-utils-lib", "android.hardware.broadcastradio@vts-utils-lib", "libgmock", ], } broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp 0 → 100644 +392 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "BcRadio.vts" #include <VtsHalHidlTargetTestBase.h> #include <android-base/logging.h> #include <android/hardware/broadcastradio/2.0/IBroadcastRadio.h> #include <android/hardware/broadcastradio/2.0/ITunerCallback.h> #include <android/hardware/broadcastradio/2.0/ITunerSession.h> #include <android/hardware/broadcastradio/2.0/types.h> #include <broadcastradio-utils-2x/Utils.h> #include <broadcastradio-vts-utils/call-barrier.h> #include <broadcastradio-vts-utils/mock-timeout.h> #include <broadcastradio-vts-utils/pointer-utils.h> #include <gmock/gmock.h> #include <chrono> namespace android { namespace hardware { namespace broadcastradio { namespace V2_0 { namespace vts { using namespace std::chrono_literals; using std::vector; using testing::_; using testing::AnyNumber; using testing::ByMove; using testing::DoAll; using testing::Invoke; using testing::SaveArg; using broadcastradio::vts::CallBarrier; using broadcastradio::vts::clearAndWait; using utils::make_identifier; using utils::make_selector_amfm; namespace timeout { static constexpr auto tune = 30s; } // namespace timeout struct TunerCallbackMock : public ITunerCallback { TunerCallbackMock() { // we expect the antenna is connected through the whole test EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0); } MOCK_METHOD2(onTuneFailed, Return<void>(Result, const ProgramSelector&)); MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChanged, Return<void>(const ProgramInfo&)); MOCK_METHOD1(onAntennaStateChange, Return<void>(bool connected)); MOCK_METHOD1(onParametersUpdated, Return<void>(const hidl_vec<VendorKeyValue>& parameters)); }; class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase { protected: virtual void SetUp() override; virtual void TearDown() override; bool openSession(); sp<IBroadcastRadio> mModule; Properties mProperties; sp<ITunerSession> mSession; sp<TunerCallbackMock> mCallback = new TunerCallbackMock(); }; void BroadcastRadioHalTest::SetUp() { EXPECT_EQ(nullptr, mModule.get()) << "Module is already open"; // lookup HIDL service (radio module) mModule = getService<IBroadcastRadio>(); ASSERT_NE(nullptr, mModule.get()) << "Couldn't find broadcast radio HAL implementation"; // get module properties auto propResult = mModule->getProperties([&](const Properties& p) { mProperties = p; }); ASSERT_TRUE(propResult.isOk()); EXPECT_FALSE(mProperties.maker.empty()); EXPECT_FALSE(mProperties.product.empty()); EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u); } void BroadcastRadioHalTest::TearDown() { mSession.clear(); mModule.clear(); clearAndWait(mCallback, 1s); } bool BroadcastRadioHalTest::openSession() { EXPECT_EQ(nullptr, mSession.get()) << "Session is already open"; Result halResult = Result::UNKNOWN_ERROR; auto openCb = [&](Result result, const sp<ITunerSession>& session) { halResult = result; if (result != Result::OK) return; mSession = session; }; auto hidlResult = mModule->openSession(mCallback, openCb); EXPECT_TRUE(hidlResult.isOk()); EXPECT_EQ(Result::OK, halResult); EXPECT_NE(nullptr, mSession.get()); return nullptr != mSession.get(); } /** * Test session opening. * * Verifies that: * - the method succeeds on a first and subsequent calls; * - the method succeeds when called for the second time without * closing previous session. */ TEST_F(BroadcastRadioHalTest, OpenSession) { // simply open session for the first time ASSERT_TRUE(openSession()); // drop (without explicit close) and re-open the session mSession.clear(); ASSERT_TRUE(openSession()); // open the second session (the first one should be forcibly closed) auto secondSession = mSession; mSession.clear(); ASSERT_TRUE(openSession()); } /** * Test tuning with FM selector. * * Verifies that: * - if AM/FM selector is not supported, the method returns NOT_SUPPORTED; * - if it is supported, the method succeeds; * - after a successful tune call, onCurrentProgramInfoChanged callback is * invoked carrying a proper selector; * - program changes exactly to what was requested. */ TEST_F(BroadcastRadioHalTest, FmTune) { ASSERT_TRUE(openSession()); uint64_t freq = 100100; // 100.1 FM auto sel = make_selector_amfm(freq); // try tuning ProgramInfo infoCb = {}; EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _) .Times(AnyNumber()) .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(Void())))); auto result = mSession->tune(sel); // expect a failure if it's not supported if (!utils::isSupported(mProperties, sel)) { EXPECT_EQ(Result::NOT_SUPPORTED, result); return; } // expect a callback if it succeeds EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune); // 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)); } /** * Test tuning with invalid selectors. * * Verifies that: * - if the selector is not supported, it's ignored; * - if it is supported, an invalid value results with INVALID_ARGUMENTS; */ TEST_F(BroadcastRadioHalTest, TuneFailsWithInvalid) { ASSERT_TRUE(openSession()); vector<ProgramIdentifier> invalid = { make_identifier(IdentifierType::AMFM_FREQUENCY, 0), make_identifier(IdentifierType::RDS_PI, 0x10000), make_identifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000), make_identifier(IdentifierType::DAB_SID_EXT, 0), make_identifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000), make_identifier(IdentifierType::SXM_SERVICE_ID, 0x100000000), }; for (auto&& id : invalid) { ProgramSelector sel{id, {}}; auto result = mSession->tune(sel); if (utils::isSupported(mProperties, sel)) { EXPECT_EQ(Result::INVALID_ARGUMENTS, result); } else { EXPECT_EQ(Result::NOT_SUPPORTED, result); } } } /** * Test tuning with empty program selector. * * Verifies that: * - tune fails with NOT_SUPPORTED when program selector is not initialized. */ TEST_F(BroadcastRadioHalTest, TuneFailsWithEmpty) { ASSERT_TRUE(openSession()); // Program type is 1-based, so 0 will always be invalid. ProgramSelector sel = {}; auto result = mSession->tune(sel); ASSERT_EQ(Result::NOT_SUPPORTED, result); } /** * Test scanning to next/prev station. * * Verifies that: * - the method succeeds; * - the program info is changed within timeout::tune; * - works both directions and with or without skipping sub-channel. */ TEST_F(BroadcastRadioHalTest, Scan) { ASSERT_TRUE(openSession()); EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _); auto result = mSession->scan(true /* up */, true /* skip subchannel */); EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune); EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _); result = mSession->scan(false /* down */, false /* don't skip subchannel */); EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune); } /** * Test step operation. * * Verifies that: * - the method succeeds or returns NOT_SUPPORTED; * - the program info is changed within timeout::tune if the method succeeded; * - works both directions. */ TEST_F(BroadcastRadioHalTest, Step) { ASSERT_TRUE(openSession()); EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _).Times(AnyNumber()); auto result = mSession->step(true /* up */); if (result == Result::NOT_SUPPORTED) return; EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune); EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _); result = mSession->step(false /* down */); EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune); } /** * Test tune cancellation. * * Verifies that: * - the method does not crash after being invoked multiple times. */ TEST_F(BroadcastRadioHalTest, Cancel) { ASSERT_TRUE(openSession()); for (int i = 0; i < 10; i++) { auto scanResult = mSession->scan(true /* up */, true /* skip subchannel */); ASSERT_EQ(Result::OK, scanResult); auto cancelResult = mSession->cancel(); ASSERT_TRUE(cancelResult.isOk()); } } /** * Test IBroadcastRadio::get|setParameters() methods called with no parameters. * * Verifies that: * - callback is called for empty parameters set. */ TEST_F(BroadcastRadioHalTest, NoParameters) { ASSERT_TRUE(openSession()); hidl_vec<VendorKeyValue> halResults = {}; bool wasCalled = false; auto cb = [&](hidl_vec<VendorKeyValue> results) { wasCalled = true; halResults = results; }; auto hidlResult = mSession->setParameters({}, cb); ASSERT_TRUE(hidlResult.isOk()); ASSERT_TRUE(wasCalled); ASSERT_EQ(0u, halResults.size()); wasCalled = false; hidlResult = mSession->getParameters({}, cb); ASSERT_TRUE(hidlResult.isOk()); ASSERT_TRUE(wasCalled); ASSERT_EQ(0u, halResults.size()); } /** * Test IBroadcastRadio::get|setParameters() methods called with unknown parameters. * * Verifies that: * - unknown parameters are ignored; * - callback is called also for empty results set. */ TEST_F(BroadcastRadioHalTest, UnknownParameters) { ASSERT_TRUE(openSession()); hidl_vec<VendorKeyValue> halResults = {}; bool wasCalled = false; auto cb = [&](hidl_vec<VendorKeyValue> results) { wasCalled = true; halResults = results; }; auto hidlResult = mSession->setParameters({{"com.google.unknown", "dummy"}}, cb); ASSERT_TRUE(hidlResult.isOk()); ASSERT_TRUE(wasCalled); ASSERT_EQ(0u, halResults.size()); wasCalled = false; hidlResult = mSession->getParameters({{"com.google.unknown*", "dummy"}}, cb); ASSERT_TRUE(hidlResult.isOk()); ASSERT_TRUE(wasCalled); ASSERT_EQ(0u, halResults.size()); } /** * Test session closing. * * Verifies that: * - the method does not crash after being invoked multiple times. */ TEST_F(BroadcastRadioHalTest, Close) { ASSERT_TRUE(openSession()); for (int i = 0; i < 10; i++) { auto cancelResult = mSession->close(); ASSERT_TRUE(cancelResult.isOk()); } } /** * Test geting image of invalid ID. * * Verifies that: * - getImage call handles argument 0 gracefully. */ TEST_F(BroadcastRadioHalTest, GetNoImage) { size_t len = 0; auto result = mModule->getImage(0, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); }); ASSERT_TRUE(result.isOk()); ASSERT_EQ(0u, len); } } // namespace vts } // namespace V2_0 } // namespace broadcastradio } // namespace hardware } // namespace android int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); int status = RUN_ALL_TESTS(); ALOGI("Test result = %d", status); return status; } Loading
broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp +2 −23 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include <broadcastradio-utils-1x/Utils.h> #include <broadcastradio-vts-utils/call-barrier.h> #include <broadcastradio-vts-utils/mock-timeout.h> #include <broadcastradio-vts-utils/pointer-utils.h> #include <cutils/native_handle.h> #include <cutils/properties.h> #include <gmock/gmock.h> Loading Loading @@ -56,8 +57,7 @@ using V1_0::MetaData; using V1_0::MetadataKey; using V1_0::MetadataType; using std::chrono::steady_clock; using std::this_thread::sleep_for; using broadcastradio::vts::clearAndWait; static constexpr auto kConfigTimeout = 10s; static constexpr auto kConnectModuleTimeout = 1s; Loading Loading @@ -115,27 +115,6 @@ class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase, hidl_vec<BandConfig> mBands; }; /** * Clears strong pointer and waits until the object gets destroyed. * * @param ptr The pointer to get cleared. * @param timeout Time to wait for other references. */ template <typename T> static void clearAndWait(sp<T>& ptr, std::chrono::milliseconds timeout) { wp<T> wptr = ptr; ptr.clear(); auto limit = steady_clock::now() + timeout; while (wptr.promote() != nullptr) { constexpr auto step = 10ms; if (steady_clock::now() + step > limit) { FAIL() << "Pointer was not released within timeout"; break; } sleep_for(step); } } void BroadcastRadioHalTest::SetUp() { radioClass = GetParam(); Loading
broadcastradio/1.2/vts/functional/VtsHalBroadcastradioV1_2TargetTest.cpp +3 −24 Original line number Diff line number Diff line Loading @@ -17,14 +17,15 @@ #define LOG_TAG "broadcastradio.vts" #include <VtsHalHidlTargetTestBase.h> #include <android-base/logging.h> #include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h> #include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h> #include <android/hardware/broadcastradio/1.2/ITuner.h> #include <android/hardware/broadcastradio/1.2/ITunerCallback.h> #include <android/hardware/broadcastradio/1.2/types.h> #include <android-base/logging.h> #include <broadcastradio-vts-utils/call-barrier.h> #include <broadcastradio-vts-utils/mock-timeout.h> #include <broadcastradio-vts-utils/pointer-utils.h> #include <cutils/native_handle.h> #include <cutils/properties.h> #include <gmock/gmock.h> Loading Loading @@ -60,8 +61,7 @@ using V1_1::ProgramListResult; using V1_1::ProgramSelector; using V1_1::Properties; using std::chrono::steady_clock; using std::this_thread::sleep_for; using broadcastradio::vts::clearAndWait; static constexpr auto kConfigTimeout = 10s; static constexpr auto kConnectModuleTimeout = 1s; Loading Loading @@ -110,27 +110,6 @@ class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase, hidl_vec<BandConfig> mBands; }; /** * Clears strong pointer and waits until the object gets destroyed. * * @param ptr The pointer to get cleared. * @param timeout Time to wait for other references. */ template <typename T> static void clearAndWait(sp<T>& ptr, std::chrono::milliseconds timeout) { wp<T> wptr = ptr; ptr.clear(); auto limit = steady_clock::now() + timeout; while (wptr.promote() != nullptr) { constexpr auto step = 10ms; if (steady_clock::now() + step > limit) { FAIL() << "Pointer was not released within timeout"; break; } sleep_for(step); } } void BroadcastRadioHalTest::SetUp() { radioClass = GetParam(); Loading
broadcastradio/2.0/vts/OWNERS 0 → 100644 +7 −0 Original line number Diff line number Diff line # Automotive team egranata@google.com twasilczyk@google.com # VTS team yuexima@google.com yim@google.com
broadcastradio/2.0/vts/functional/Android.bp 0 → 100644 +28 −0 Original line number Diff line number Diff line // // Copyright (C) 2017 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // cc_test { name: "VtsHalBroadcastradioV2_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalBroadcastradioV2_0TargetTest.cpp"], static_libs: [ "android.hardware.broadcastradio@2.0", "android.hardware.broadcastradio@common-utils-2x-lib", "android.hardware.broadcastradio@vts-utils-lib", "android.hardware.broadcastradio@vts-utils-lib", "libgmock", ], }
broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp 0 → 100644 +392 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "BcRadio.vts" #include <VtsHalHidlTargetTestBase.h> #include <android-base/logging.h> #include <android/hardware/broadcastradio/2.0/IBroadcastRadio.h> #include <android/hardware/broadcastradio/2.0/ITunerCallback.h> #include <android/hardware/broadcastradio/2.0/ITunerSession.h> #include <android/hardware/broadcastradio/2.0/types.h> #include <broadcastradio-utils-2x/Utils.h> #include <broadcastradio-vts-utils/call-barrier.h> #include <broadcastradio-vts-utils/mock-timeout.h> #include <broadcastradio-vts-utils/pointer-utils.h> #include <gmock/gmock.h> #include <chrono> namespace android { namespace hardware { namespace broadcastradio { namespace V2_0 { namespace vts { using namespace std::chrono_literals; using std::vector; using testing::_; using testing::AnyNumber; using testing::ByMove; using testing::DoAll; using testing::Invoke; using testing::SaveArg; using broadcastradio::vts::CallBarrier; using broadcastradio::vts::clearAndWait; using utils::make_identifier; using utils::make_selector_amfm; namespace timeout { static constexpr auto tune = 30s; } // namespace timeout struct TunerCallbackMock : public ITunerCallback { TunerCallbackMock() { // we expect the antenna is connected through the whole test EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0); } MOCK_METHOD2(onTuneFailed, Return<void>(Result, const ProgramSelector&)); MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChanged, Return<void>(const ProgramInfo&)); MOCK_METHOD1(onAntennaStateChange, Return<void>(bool connected)); MOCK_METHOD1(onParametersUpdated, Return<void>(const hidl_vec<VendorKeyValue>& parameters)); }; class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase { protected: virtual void SetUp() override; virtual void TearDown() override; bool openSession(); sp<IBroadcastRadio> mModule; Properties mProperties; sp<ITunerSession> mSession; sp<TunerCallbackMock> mCallback = new TunerCallbackMock(); }; void BroadcastRadioHalTest::SetUp() { EXPECT_EQ(nullptr, mModule.get()) << "Module is already open"; // lookup HIDL service (radio module) mModule = getService<IBroadcastRadio>(); ASSERT_NE(nullptr, mModule.get()) << "Couldn't find broadcast radio HAL implementation"; // get module properties auto propResult = mModule->getProperties([&](const Properties& p) { mProperties = p; }); ASSERT_TRUE(propResult.isOk()); EXPECT_FALSE(mProperties.maker.empty()); EXPECT_FALSE(mProperties.product.empty()); EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u); } void BroadcastRadioHalTest::TearDown() { mSession.clear(); mModule.clear(); clearAndWait(mCallback, 1s); } bool BroadcastRadioHalTest::openSession() { EXPECT_EQ(nullptr, mSession.get()) << "Session is already open"; Result halResult = Result::UNKNOWN_ERROR; auto openCb = [&](Result result, const sp<ITunerSession>& session) { halResult = result; if (result != Result::OK) return; mSession = session; }; auto hidlResult = mModule->openSession(mCallback, openCb); EXPECT_TRUE(hidlResult.isOk()); EXPECT_EQ(Result::OK, halResult); EXPECT_NE(nullptr, mSession.get()); return nullptr != mSession.get(); } /** * Test session opening. * * Verifies that: * - the method succeeds on a first and subsequent calls; * - the method succeeds when called for the second time without * closing previous session. */ TEST_F(BroadcastRadioHalTest, OpenSession) { // simply open session for the first time ASSERT_TRUE(openSession()); // drop (without explicit close) and re-open the session mSession.clear(); ASSERT_TRUE(openSession()); // open the second session (the first one should be forcibly closed) auto secondSession = mSession; mSession.clear(); ASSERT_TRUE(openSession()); } /** * Test tuning with FM selector. * * Verifies that: * - if AM/FM selector is not supported, the method returns NOT_SUPPORTED; * - if it is supported, the method succeeds; * - after a successful tune call, onCurrentProgramInfoChanged callback is * invoked carrying a proper selector; * - program changes exactly to what was requested. */ TEST_F(BroadcastRadioHalTest, FmTune) { ASSERT_TRUE(openSession()); uint64_t freq = 100100; // 100.1 FM auto sel = make_selector_amfm(freq); // try tuning ProgramInfo infoCb = {}; EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _) .Times(AnyNumber()) .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(Void())))); auto result = mSession->tune(sel); // expect a failure if it's not supported if (!utils::isSupported(mProperties, sel)) { EXPECT_EQ(Result::NOT_SUPPORTED, result); return; } // expect a callback if it succeeds EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune); // 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)); } /** * Test tuning with invalid selectors. * * Verifies that: * - if the selector is not supported, it's ignored; * - if it is supported, an invalid value results with INVALID_ARGUMENTS; */ TEST_F(BroadcastRadioHalTest, TuneFailsWithInvalid) { ASSERT_TRUE(openSession()); vector<ProgramIdentifier> invalid = { make_identifier(IdentifierType::AMFM_FREQUENCY, 0), make_identifier(IdentifierType::RDS_PI, 0x10000), make_identifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000), make_identifier(IdentifierType::DAB_SID_EXT, 0), make_identifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000), make_identifier(IdentifierType::SXM_SERVICE_ID, 0x100000000), }; for (auto&& id : invalid) { ProgramSelector sel{id, {}}; auto result = mSession->tune(sel); if (utils::isSupported(mProperties, sel)) { EXPECT_EQ(Result::INVALID_ARGUMENTS, result); } else { EXPECT_EQ(Result::NOT_SUPPORTED, result); } } } /** * Test tuning with empty program selector. * * Verifies that: * - tune fails with NOT_SUPPORTED when program selector is not initialized. */ TEST_F(BroadcastRadioHalTest, TuneFailsWithEmpty) { ASSERT_TRUE(openSession()); // Program type is 1-based, so 0 will always be invalid. ProgramSelector sel = {}; auto result = mSession->tune(sel); ASSERT_EQ(Result::NOT_SUPPORTED, result); } /** * Test scanning to next/prev station. * * Verifies that: * - the method succeeds; * - the program info is changed within timeout::tune; * - works both directions and with or without skipping sub-channel. */ TEST_F(BroadcastRadioHalTest, Scan) { ASSERT_TRUE(openSession()); EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _); auto result = mSession->scan(true /* up */, true /* skip subchannel */); EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune); EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _); result = mSession->scan(false /* down */, false /* don't skip subchannel */); EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune); } /** * Test step operation. * * Verifies that: * - the method succeeds or returns NOT_SUPPORTED; * - the program info is changed within timeout::tune if the method succeeded; * - works both directions. */ TEST_F(BroadcastRadioHalTest, Step) { ASSERT_TRUE(openSession()); EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _).Times(AnyNumber()); auto result = mSession->step(true /* up */); if (result == Result::NOT_SUPPORTED) return; EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune); EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _); result = mSession->step(false /* down */); EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune); } /** * Test tune cancellation. * * Verifies that: * - the method does not crash after being invoked multiple times. */ TEST_F(BroadcastRadioHalTest, Cancel) { ASSERT_TRUE(openSession()); for (int i = 0; i < 10; i++) { auto scanResult = mSession->scan(true /* up */, true /* skip subchannel */); ASSERT_EQ(Result::OK, scanResult); auto cancelResult = mSession->cancel(); ASSERT_TRUE(cancelResult.isOk()); } } /** * Test IBroadcastRadio::get|setParameters() methods called with no parameters. * * Verifies that: * - callback is called for empty parameters set. */ TEST_F(BroadcastRadioHalTest, NoParameters) { ASSERT_TRUE(openSession()); hidl_vec<VendorKeyValue> halResults = {}; bool wasCalled = false; auto cb = [&](hidl_vec<VendorKeyValue> results) { wasCalled = true; halResults = results; }; auto hidlResult = mSession->setParameters({}, cb); ASSERT_TRUE(hidlResult.isOk()); ASSERT_TRUE(wasCalled); ASSERT_EQ(0u, halResults.size()); wasCalled = false; hidlResult = mSession->getParameters({}, cb); ASSERT_TRUE(hidlResult.isOk()); ASSERT_TRUE(wasCalled); ASSERT_EQ(0u, halResults.size()); } /** * Test IBroadcastRadio::get|setParameters() methods called with unknown parameters. * * Verifies that: * - unknown parameters are ignored; * - callback is called also for empty results set. */ TEST_F(BroadcastRadioHalTest, UnknownParameters) { ASSERT_TRUE(openSession()); hidl_vec<VendorKeyValue> halResults = {}; bool wasCalled = false; auto cb = [&](hidl_vec<VendorKeyValue> results) { wasCalled = true; halResults = results; }; auto hidlResult = mSession->setParameters({{"com.google.unknown", "dummy"}}, cb); ASSERT_TRUE(hidlResult.isOk()); ASSERT_TRUE(wasCalled); ASSERT_EQ(0u, halResults.size()); wasCalled = false; hidlResult = mSession->getParameters({{"com.google.unknown*", "dummy"}}, cb); ASSERT_TRUE(hidlResult.isOk()); ASSERT_TRUE(wasCalled); ASSERT_EQ(0u, halResults.size()); } /** * Test session closing. * * Verifies that: * - the method does not crash after being invoked multiple times. */ TEST_F(BroadcastRadioHalTest, Close) { ASSERT_TRUE(openSession()); for (int i = 0; i < 10; i++) { auto cancelResult = mSession->close(); ASSERT_TRUE(cancelResult.isOk()); } } /** * Test geting image of invalid ID. * * Verifies that: * - getImage call handles argument 0 gracefully. */ TEST_F(BroadcastRadioHalTest, GetNoImage) { size_t len = 0; auto result = mModule->getImage(0, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); }); ASSERT_TRUE(result.isOk()); ASSERT_EQ(0u, len); } } // namespace vts } // namespace V2_0 } // namespace broadcastradio } // namespace hardware } // namespace android int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); int status = RUN_ALL_TESTS(); ALOGI("Test result = %d", status); return status; }