| // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "shill/cellular/mobile_operator_info.h" |
| |
| #include <map> |
| #include <memory> |
| #include <set> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/check_op.h> |
| #include <base/files/file_path.h> |
| #include <base/macros.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "shill/cellular/mobile_operator_info_impl.h" |
| #include "shill/logging.h" |
| #include "shill/test_event_dispatcher.h" |
| |
| using testing::Mock; |
| using testing::Test; |
| using testing::Values; |
| using testing::WithParamInterface; |
| |
| // The tests run from the fixture |MobileOperatorInfoMainTest| and |
| // |MobileOperatorDataTest| can be run in two modes: |
| // - strict event checking: We check that an event is raised for each update |
| // to the state of the object. |
| // - non-strict event checking: We check that a single event is raised as a |
| // result of many updates to the object. |
| // The first case corresponds to a very aggressive event loop, that dispatches |
| // events as soon as they are posted; the second one corresponds to an |
| // over-crowded event loop that only dispatches events just before we verify |
| // that events were raised. |
| // |
| // We use ::testing::WithParamInterface to templatize the test fixtures to do |
| // string/non-strict event checking. When writing test cases using these |
| // fixtures, use the |Update*|, |ExpectEventCount|, |VerifyEventCount| functions |
| // provided by the fixture, and write the test as if event checking is strict. |
| // |
| // For |MobileOperatorObserverTest|, only the strict event checking case makes |
| // sense, so we only instantiate that. |
| namespace shill { |
| |
| namespace { |
| |
| enum EventCheckingPolicy { |
| kEventCheckingPolicyStrict, |
| kEventCheckingPolicyNonStrict |
| }; |
| |
| base::FilePath GetTestProtoPath(const std::string& file) { |
| const char* out_dir = getenv("OUT"); |
| CHECK_NE(out_dir, nullptr); |
| return base::FilePath(out_dir).Append(file); |
| } |
| |
| } // namespace |
| |
| class MockMobileOperatorInfoObserver : public MobileOperatorInfo::Observer { |
| public: |
| MockMobileOperatorInfoObserver() = default; |
| |
| MOCK_METHOD(void, OnOperatorChanged, (), (override)); |
| }; |
| |
| class MobileOperatorInfoInitTest : public Test { |
| public: |
| MobileOperatorInfoInitTest() |
| : operator_info_(new MobileOperatorInfo(&dispatcher_, "Operator")), |
| operator_info_impl_(operator_info_->impl()) {} |
| MobileOperatorInfoInitTest(const MobileOperatorInfoInitTest&) = delete; |
| MobileOperatorInfoInitTest& operator=(const MobileOperatorInfoInitTest&) = |
| delete; |
| |
| protected: |
| bool SetUpDatabase(const std::vector<std::string>& files) { |
| operator_info_->ClearDatabasePaths(); |
| for (const auto& file : files) { |
| operator_info_->AddDatabasePath(GetTestProtoPath(file)); |
| } |
| return operator_info_->Init(); |
| } |
| |
| void AssertDatabaseEmpty() { |
| EXPECT_EQ(0, operator_info_impl_->database()->mno_size()); |
| EXPECT_EQ(0, operator_info_impl_->database()->mvno_size()); |
| } |
| |
| const shill::mobile_operator_db::MobileOperatorDB* GetDatabase() { |
| return operator_info_impl_->database(); |
| } |
| |
| EventDispatcherForTest dispatcher_; |
| std::unique_ptr<MobileOperatorInfo> operator_info_; |
| // Owned by |operator_info_| and tied to its life cycle. |
| MobileOperatorInfoImpl* operator_info_impl_; |
| }; |
| |
| TEST_F(MobileOperatorInfoInitTest, FailedInitNoPath) { |
| // - Initialize object with no database paths set |
| // - Verify that initialization fails. |
| operator_info_->ClearDatabasePaths(); |
| EXPECT_FALSE(operator_info_->Init()); |
| AssertDatabaseEmpty(); |
| } |
| |
| TEST_F(MobileOperatorInfoInitTest, FailedInitBadPath) { |
| // - Initialize object with non-existent path. |
| // - Verify that initialization fails. |
| EXPECT_FALSE(SetUpDatabase({"nonexistent.pbf"})); |
| AssertDatabaseEmpty(); |
| } |
| |
| TEST_F(MobileOperatorInfoInitTest, FailedInitBadDatabase) { |
| // - Initialize object with malformed database. |
| // - Verify that initialization fails. |
| // TODO(pprabhu): It's hard to get a malformed database in binary format. |
| } |
| |
| TEST_F(MobileOperatorInfoInitTest, EmptyDBInit) { |
| // - Initialize the object with a database file that is empty. |
| // - Verify that initialization succeeds, and that the database is empty. |
| EXPECT_TRUE(SetUpDatabase({"init_test_empty_db_init.pbf"})); |
| AssertDatabaseEmpty(); |
| } |
| |
| TEST_F(MobileOperatorInfoInitTest, SuccessfulInit) { |
| EXPECT_TRUE(SetUpDatabase({"init_test_successful_init.pbf"})); |
| EXPECT_GT(GetDatabase()->mno_size(), 0); |
| EXPECT_GT(GetDatabase()->mvno_size(), 0); |
| } |
| |
| TEST_F(MobileOperatorInfoInitTest, MultipleDBInit) { |
| // - Initialize the object with two database files. |
| // - Verify that intialization succeeds, and both databases are loaded. |
| EXPECT_TRUE(SetUpDatabase({"init_test_multiple_db_init_1.pbf", |
| "init_test_multiple_db_init_2.pbf"})); |
| EXPECT_TRUE(operator_info_->Init()); |
| EXPECT_GT(GetDatabase()->mno_size(), 0); |
| EXPECT_GT(GetDatabase()->mvno_size(), 0); |
| } |
| |
| TEST_F(MobileOperatorInfoInitTest, InitWithObserver) { |
| // - Add an Observer. |
| // - Initialize the object with empty database file. |
| // - Verify innitialization succeeds. |
| MockMobileOperatorInfoObserver dumb_observer; |
| |
| EXPECT_TRUE(SetUpDatabase({"init_test_empty_db_init.pbf"})); |
| operator_info_->AddObserver(&dumb_observer); |
| EXPECT_TRUE(operator_info_->Init()); |
| } |
| |
| class MobileOperatorInfoMainTest |
| : public MobileOperatorInfoInitTest, |
| public WithParamInterface<EventCheckingPolicy> { |
| public: |
| MobileOperatorInfoMainTest() : event_checking_policy_(GetParam()) {} |
| MobileOperatorInfoMainTest(const MobileOperatorInfoMainTest&) = delete; |
| MobileOperatorInfoMainTest& operator=(const MobileOperatorInfoMainTest&) = |
| delete; |
| |
| void SetUp() override { |
| EXPECT_TRUE(SetUpDatabase({"main_test.pbf"})); |
| operator_info_->AddObserver(&observer_); |
| } |
| |
| protected: |
| // /////////////////////////////////////////////////////////////////////////// |
| // Helper functions. |
| void VerifyMNOWithUUID(const std::string& uuid) { |
| EXPECT_TRUE(operator_info_->IsMobileNetworkOperatorKnown()); |
| EXPECT_FALSE(operator_info_->IsMobileVirtualNetworkOperatorKnown()); |
| EXPECT_EQ(uuid, operator_info_->uuid()); |
| } |
| |
| void VerifyMVNOWithUUID(const std::string& uuid) { |
| EXPECT_TRUE(operator_info_->IsMobileNetworkOperatorKnown()); |
| EXPECT_TRUE(operator_info_->IsMobileVirtualNetworkOperatorKnown()); |
| EXPECT_EQ(uuid, operator_info_->uuid()); |
| } |
| |
| void VerifyNoMatch() { |
| EXPECT_FALSE(operator_info_->IsMobileNetworkOperatorKnown()); |
| EXPECT_FALSE(operator_info_->IsMobileVirtualNetworkOperatorKnown()); |
| EXPECT_EQ("", operator_info_->uuid()); |
| } |
| |
| void ExpectEventCount(int count) { |
| // In case we're running in the non-strict event checking mode, we only |
| // expect one overall event to be raised for all the updates. |
| if (event_checking_policy_ == kEventCheckingPolicyNonStrict) { |
| count = (count > 0) ? 1 : 0; |
| } |
| EXPECT_CALL(observer_, OnOperatorChanged()).Times(count); |
| } |
| |
| void VerifyEventCount() { |
| dispatcher_.DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&observer_); |
| } |
| |
| void ResetOperatorInfo() { |
| operator_info_->Reset(); |
| // Eat up any events caused by |Reset|. |
| dispatcher_.DispatchPendingEvents(); |
| VerifyNoMatch(); |
| } |
| |
| // Use these wrappers to send updates to |operator_info_|. These wrappers |
| // optionally run the dispatcher if we want strict checking of the number of |
| // events raised. |
| void UpdateMCCMNC(const std::string& mccmnc) { |
| operator_info_->UpdateMCCMNC(mccmnc); |
| DispatchPendingEventsIfStrict(); |
| } |
| |
| void UpdateSID(const std::string& sid) { |
| operator_info_->UpdateSID(sid); |
| DispatchPendingEventsIfStrict(); |
| } |
| |
| void UpdateIMSI(const std::string& imsi) { |
| operator_info_->UpdateIMSI(imsi); |
| DispatchPendingEventsIfStrict(); |
| } |
| |
| void UpdateICCID(const std::string& iccid) { |
| operator_info_->UpdateICCID(iccid); |
| DispatchPendingEventsIfStrict(); |
| } |
| |
| void UpdateNID(const std::string& nid) { |
| operator_info_->UpdateNID(nid); |
| DispatchPendingEventsIfStrict(); |
| } |
| |
| void UpdateOperatorName(const std::string& operator_name) { |
| operator_info_->UpdateOperatorName(operator_name); |
| DispatchPendingEventsIfStrict(); |
| } |
| |
| void UpdateOnlinePortal(const std::string& url, |
| const std::string& method, |
| const std::string& post_data) { |
| operator_info_->UpdateOnlinePortal(url, method, post_data); |
| DispatchPendingEventsIfStrict(); |
| } |
| |
| void DispatchPendingEventsIfStrict() { |
| if (event_checking_policy_ == kEventCheckingPolicyStrict) { |
| dispatcher_.DispatchPendingEvents(); |
| } |
| } |
| |
| // /////////////////////////////////////////////////////////////////////////// |
| // Data. |
| MockMobileOperatorInfoObserver observer_; |
| const EventCheckingPolicy event_checking_policy_; |
| }; |
| |
| TEST_P(MobileOperatorInfoMainTest, InitialConditions) { |
| // - Initialize a new object. |
| // - Verify that all initial values of properties are reasonable. |
| EXPECT_FALSE(operator_info_->IsMobileNetworkOperatorKnown()); |
| EXPECT_FALSE(operator_info_->IsMobileVirtualNetworkOperatorKnown()); |
| EXPECT_TRUE(operator_info_->uuid().empty()); |
| EXPECT_TRUE(operator_info_->operator_name().empty()); |
| EXPECT_TRUE(operator_info_->country().empty()); |
| EXPECT_TRUE(operator_info_->mccmnc().empty()); |
| EXPECT_TRUE(operator_info_->sid().empty()); |
| EXPECT_TRUE(operator_info_->nid().empty()); |
| EXPECT_TRUE(operator_info_->mccmnc_list().empty()); |
| EXPECT_TRUE(operator_info_->sid_list().empty()); |
| EXPECT_TRUE(operator_info_->operator_name_list().empty()); |
| EXPECT_TRUE(operator_info_->apn_list().empty()); |
| EXPECT_TRUE(operator_info_->olp_list().empty()); |
| EXPECT_TRUE(operator_info_->activation_code().empty()); |
| EXPECT_FALSE(operator_info_->requires_roaming()); |
| EXPECT_EQ(0, operator_info_->mtu()); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOByMCCMNC) { |
| // message: Has an MNO with no MVNO. |
| // match by: MCCMNC. |
| // verify: Observer event, uuid. |
| |
| ExpectEventCount(0); |
| UpdateMCCMNC("101999"); // No match. |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| |
| ExpectEventCount(1); |
| UpdateMCCMNC("101001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid101"); |
| |
| ExpectEventCount(1); |
| UpdateMCCMNC("101999"); |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOByMCCMNCMultipleMCCMNCOptions) { |
| // message: Has an MNO with no MCCMNC. |
| // match by: One of the MCCMNCs of the multiple ones in the MNO. |
| // verify: Observer event, uuid. |
| ExpectEventCount(1); |
| UpdateMCCMNC("102002"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid102"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOByMCCMNCMultipleMNOOptions) { |
| // message: Two messages with the same MCCMNC. |
| // match by: Both MNOs matched, one is earmarked. |
| // verify: The earmarked MNO is picked. |
| ExpectEventCount(1); |
| UpdateMCCMNC("124001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid124002"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOByOperatorName) { |
| // message: Has an MNO with no MVNO. |
| // match by: OperatorName. |
| // verify: Observer event, uuid. |
| ExpectEventCount(0); |
| UpdateOperatorName("name103999"); // No match. |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| |
| ExpectEventCount(1); |
| UpdateOperatorName("name103"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid103"); |
| |
| ExpectEventCount(1); |
| UpdateOperatorName("name103999"); // No match. |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOByOperatorNameMultipleMNOOptions) { |
| // message: Two messages with the same operator name. |
| // match by: Both MNOs matched, one is earmarked. |
| // verify: The earmarked MNO is picked. |
| ExpectEventCount(1); |
| UpdateOperatorName("name125001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid125002"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOByOperatorNameAggressiveMatch) { |
| // These network operators match by name but only after normalizing the names. |
| // Both the name from the database and the name provided to |
| // |UpdateOperatoName| must be normalized for this test to pass. |
| ExpectEventCount(1); |
| UpdateOperatorName("name126001 casedoesnotmatch"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid126001"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(1); |
| UpdateOperatorName("name126002 CaseStillDoesNotMatch"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid126002"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(1); |
| UpdateOperatorName("name126003GiveMeMoreSpace"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid126003"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(1); |
| UpdateOperatorName("name126004 Too Much Air Here"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid126004"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(1); |
| UpdateOperatorName("näméwithNon-Äσ¢ii"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid126005"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOByOperatorNameWithLang) { |
| // message: Has an MNO with no MVNO. |
| // match by: OperatorName. |
| // verify: Observer event, fields. |
| ExpectEventCount(1); |
| UpdateOperatorName("name105"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid105"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOByOperatorNameMultipleNameOptions) { |
| // message: Has an MNO with no MVNO. |
| // match by: OperatorName, one of the multiple present in the MNO. |
| // verify: Observer event, fields. |
| ExpectEventCount(1); |
| UpdateOperatorName("name104002"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid104"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOByMCCMNCAndOperatorName) { |
| // message: Has MNOs with no MVNO. |
| // match by: MCCMNC finds two candidates (first one is chosen), Name narrows |
| // down to one. |
| // verify: Observer event, fields. |
| // This is merely a MCCMNC update. |
| ExpectEventCount(1); |
| UpdateMCCMNC("106001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid106001"); |
| |
| ExpectEventCount(1); |
| UpdateOperatorName("name106002"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid106002"); |
| |
| ResetOperatorInfo(); |
| // Try updates in reverse order. |
| ExpectEventCount(1); |
| UpdateOperatorName("name106001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid106001"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOByOperatorNameAndMCCMNC) { |
| // message: Has MNOs with no MVNO. |
| // match by: OperatorName finds two (first one is chosen), MCCMNC narrows down |
| // to one. |
| // verify: Observer event, fields. |
| // This is merely an OperatorName update. |
| ExpectEventCount(1); |
| UpdateOperatorName("name107"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid107001"); |
| |
| ExpectEventCount(1); |
| UpdateMCCMNC("107002"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid107002"); |
| |
| ResetOperatorInfo(); |
| // Try updates in reverse order. |
| ExpectEventCount(1); |
| UpdateMCCMNC("107001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid107001"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOByMCCMNCOverridesOperatorName) { |
| // message: Has MNOs with no MVNO. |
| // match by: First MCCMNC finds one. Then, OperatorName matches another. |
| // verify: MCCMNC match prevails. No change on OperatorName update. |
| ExpectEventCount(1); |
| UpdateMCCMNC("108001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid108001"); |
| |
| // An event is sent for the updated OperatorName. |
| ExpectEventCount(1); |
| UpdateOperatorName("name108002"); // Does not match. |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid108001"); |
| // OperatorName will display the user supplied operator, but this shouldn't |
| // change the operator. |
| EXPECT_EQ("name108002", operator_info_->operator_name()); |
| |
| ResetOperatorInfo(); |
| // message: Same as above. |
| // match by: First OperatorName finds one, then MCCMNC overrides it. |
| // verify: Two events, MCCMNC one overriding the OperatorName one. |
| ExpectEventCount(1); |
| UpdateOperatorName("name108001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid108001"); |
| |
| ExpectEventCount(1); |
| UpdateMCCMNC("108002"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid108002"); |
| // But we still show the user supplied operator. |
| EXPECT_EQ("name108001", operator_info_->operator_name()); |
| |
| // message: Same as above. |
| // match by: First a *wrong* MCCMNC update, followed by the correct Name |
| // update. |
| // verify: No MNO, since MCCMNC is given precedence. |
| ResetOperatorInfo(); |
| ExpectEventCount(0); |
| UpdateMCCMNC("108999"); // Does not match. |
| UpdateOperatorName("name108001"); |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOByIMSI) { |
| // message: Has MNO with no MVNO. |
| // match by: MCCMNC part of IMSI of length 5 / 6. |
| ExpectEventCount(0); |
| UpdateIMSI("109"); // Too short. |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| |
| ExpectEventCount(0); |
| UpdateIMSI("109995432154321"); // No match. |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| |
| ResetOperatorInfo(); |
| // Short MCCMNC match. |
| ExpectEventCount(1); |
| UpdateIMSI("109015432154321"); // First 5 digits match. |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid10901"); |
| |
| ResetOperatorInfo(); |
| // Long MCCMNC match. |
| ExpectEventCount(1); |
| UpdateIMSI("10900215432154321"); // First 6 digits match. |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid109002"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOByMCCMNCOverridesIMSI) { |
| // message: Has MNOs with no MVNO. |
| // match by: One matches MCCMNC, then one matches a different MCCMNC substring |
| // of IMSI |
| // verify: Observer event for the first match, all fields. Second Update |
| // ignored. |
| ExpectEventCount(1); |
| UpdateMCCMNC("110001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid110001"); |
| |
| // MNO remains unchanged on a mismatched IMSI update. |
| ExpectEventCount(0); |
| UpdateIMSI("1100025432154321"); // First 6 digits match. |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid110001"); |
| |
| // MNO remains uncnaged on an invalid IMSI update. |
| ExpectEventCount(0); |
| UpdateIMSI("1100035432154321"); // Prefix does not match. |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid110001"); |
| |
| ExpectEventCount(0); |
| UpdateIMSI("110"); // Too small. |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid110001"); |
| |
| ResetOperatorInfo(); |
| // Same as above, but this time, match with IMSI, followed by a contradictory |
| // MCCMNC update. The second update should override the first one. |
| ExpectEventCount(1); |
| UpdateIMSI("1100025432154321"); // First 6 digits match. |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid110002"); |
| |
| ExpectEventCount(1); |
| UpdateMCCMNC("110001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid110001"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOUchangedBySecondaryUpdates) { |
| // This test verifies that only some updates affect the MNO. |
| // message: Has MNOs with no MVNO. |
| // match by: First matches the MCCMNC. Later, MNOs with a different MCCMNC |
| // matchs the given SID, NID, ICCID. |
| // verify: Only one Observer event, on the first MCCMNC match. |
| ExpectEventCount(1); |
| UpdateMCCMNC("111001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid111001"); |
| |
| ExpectEventCount(1); // NID change event. |
| UpdateNID("111202"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid111001"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MVNODefaultMatch) { |
| // message: MNO with one MVNO (no filter). |
| // match by: MNO matches by MCCMNC. |
| // verify: Observer event for MVNO match. Uuid match the MVNO. |
| // second update: ICCID. |
| // verify: No observer event, match remains unchanged. |
| ExpectEventCount(1); |
| UpdateMCCMNC("112001"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid112002"); |
| |
| ExpectEventCount(0); |
| UpdateICCID("112002"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid112002"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MVNONameMatch) { |
| // message: MNO with one MVNO (name filter). |
| // match by: MNO matches by MCCMNC, |
| // MVNO fails to match by fist name update, |
| // then MVNO matches by name. |
| // verify: Two Observer events: MNO followed by MVNO. |
| ExpectEventCount(1); |
| UpdateMCCMNC("113001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid113001"); |
| |
| ExpectEventCount(1); |
| UpdateOperatorName("name113999"); // No match. |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid113001"); |
| // User supplied name is still given preference. |
| EXPECT_EQ("name113999", operator_info_->operator_name()); |
| |
| ExpectEventCount(1); |
| UpdateOperatorName("name113002"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid113002"); |
| EXPECT_EQ("name113002", operator_info_->operator_name()); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MVNONameMalformedRegexMatch) { |
| // message: MNO with one MVNO (name filter with a malformed regex). |
| // match by: MNO matches by MCCMNC. |
| // MVNO does not match |
| ExpectEventCount(2); |
| UpdateMCCMNC("114001"); |
| UpdateOperatorName("name["); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid114001"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MVNONameSubexpressionRegexMatch) { |
| // message: MNO with one MVNO (name filter with simple regex). |
| // match by: MNO matches by MCCMNC. |
| // MVNO does not match with a name whose subexpression matches the |
| // regex. |
| ExpectEventCount(2); // One event for just the name update. |
| UpdateMCCMNC("115001"); |
| UpdateOperatorName("name115_ExtraCrud"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid115001"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(2); // One event for just the name update. |
| UpdateMCCMNC("115001"); |
| UpdateOperatorName("ExtraCrud_name115"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid115001"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(2); // One event for just the name update. |
| UpdateMCCMNC("115001"); |
| UpdateOperatorName("ExtraCrud_name115_ExtraCrud"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid115001"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(2); // One event for just the name update. |
| UpdateMCCMNC("115001"); |
| UpdateOperatorName("name_ExtraCrud_115"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid115001"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(2); |
| UpdateMCCMNC("115001"); |
| UpdateOperatorName("name115"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid115002"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MVNONameRegexMatch) { |
| // message: MNO with one MVNO (name filter with non-trivial regex). |
| // match by: MNO matches by MCCMNC. |
| // MVNO fails to match several times with different strings. |
| // MVNO matches several times with different values. |
| |
| // Make sure we're not taking the regex literally! |
| ExpectEventCount(2); |
| UpdateMCCMNC("116001"); |
| UpdateOperatorName("name[a-zA-Z_]*116[0-9]{0,3}"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid116001"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(2); |
| UpdateMCCMNC("116001"); |
| UpdateOperatorName("name[a-zA-Z_]116[0-9]"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid116001"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(2); |
| UpdateMCCMNC("116001"); |
| UpdateOperatorName("nameb*1167"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid116001"); |
| |
| // Success! |
| ResetOperatorInfo(); |
| ExpectEventCount(2); |
| UpdateMCCMNC("116001"); |
| UpdateOperatorName("name116"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid116002"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(2); |
| UpdateMCCMNC("116001"); |
| UpdateOperatorName("nameSomeWord116"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid116002"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(2); |
| UpdateMCCMNC("116001"); |
| UpdateOperatorName("name116567"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid116002"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MVNONameMatchMultipleFilters) { |
| // message: MNO with one MVNO with two name filters. |
| // match by: MNO matches by MCCMNC. |
| // MVNO first fails on the second filter alone. |
| // MVNO fails on the first filter alone. |
| // MVNO matches on both filters. |
| ExpectEventCount(2); |
| UpdateMCCMNC("117001"); |
| UpdateOperatorName("nameA_crud"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid117001"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(2); |
| UpdateMCCMNC("117001"); |
| UpdateOperatorName("crud_nameB"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid117001"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(2); |
| UpdateMCCMNC("117001"); |
| UpdateOperatorName("crud_crud"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid117001"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(2); |
| UpdateMCCMNC("117001"); |
| UpdateOperatorName("nameA_nameB"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid117002"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MVNOIMSIMatch) { |
| // message: MNO with one MVNO (imsi filter). |
| // match by: MNO matches by MCCMNC, |
| // MVNO fails to match by fist imsi update, |
| // then MVNO matches by imsi. |
| // verify: Two Observer events: MNO followed by MVNO. |
| // the MVNO database operator name has higher priority |
| // than the MNO name returned by the SIM. |
| ExpectEventCount(2); |
| UpdateMCCMNC("118001"); |
| UpdateOperatorName("MNO_random_name"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid118001"); |
| |
| ExpectEventCount(0); |
| UpdateIMSI("1180011234512345"); // No match. |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid118001"); |
| EXPECT_EQ("MNO_random_name", operator_info_->operator_name()); |
| |
| ExpectEventCount(1); |
| UpdateIMSI("1180015432154321"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid118002"); |
| EXPECT_EQ("name118002", operator_info_->operator_name()); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MVNOIMSIMatchByRange) { |
| // message: MNO with one MVNO (IMSI filter with 2 numerical ranges). |
| // match by: MNO matches by MCCMNC, |
| // MVNO fails to match by first IMSI update, |
| // then MVNO matches in the first IMSI, |
| // then alternately put IMSI inside and outside the ranges. |
| // verify: Observer events: alternately MNO when no match, |
| // then MVNO when match. |
| ExpectEventCount(1); |
| UpdateMCCMNC("128001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid128001"); |
| |
| ExpectEventCount(0); |
| UpdateIMSI("128001234512345"); // No match before 1st range |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid128001"); |
| |
| ExpectEventCount(1); |
| UpdateIMSI("128001432159321"); // Match, middle of 1st range |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid128002"); |
| |
| ExpectEventCount(1); |
| UpdateIMSI("128001435124321"); // No match between ranges |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid128001"); |
| |
| ExpectEventCount(1); |
| UpdateIMSI("128001438055555"); // Match, middle of 2nd range |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid128002"); |
| |
| ExpectEventCount(1); |
| UpdateIMSI("128001432154320"); // No match 1 before 1st range |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid128001"); |
| |
| ExpectEventCount(1); |
| UpdateIMSI("128001437999999"); // Match, first of 2nd range |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid128002"); |
| |
| ExpectEventCount(1); |
| UpdateIMSI("128001432164322"); // No match 1 after 1st range |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid128001"); |
| |
| ExpectEventCount(1); |
| UpdateIMSI("128001438111111"); // Match, last of 2nd range |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid128002"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MVNOICCIDMatch) { |
| // message: MNO with one MVNO (iccid filter). |
| // match by: MNO matches by MCCMNC, |
| // MVNO fails to match by fist iccid update, |
| // then MVNO matches by iccid. |
| // verify: Two Observer events: MNO followed by MVNO. |
| ExpectEventCount(1); |
| UpdateMCCMNC("119001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid119001"); |
| |
| ExpectEventCount(0); |
| UpdateICCID("119987654321"); // No match. |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid119001"); |
| |
| ExpectEventCount(1); |
| UpdateICCID("119123456789"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid119002"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MVNOSIDMatch) { |
| // message: MNO with one MVNO (sid filter). |
| // match by: MNO matches by SID, |
| // MVNO fails to match by fist sid update, |
| // then MVNO matches by sid. |
| // verify: Two Observer events: MNO followed by MVNO. |
| ExpectEventCount(0); |
| UpdateSID("120999"); // No match. |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| |
| ExpectEventCount(1); |
| UpdateSID("120001"); // Only MNO matches. |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid120001"); |
| EXPECT_EQ("120001", operator_info_->sid()); |
| |
| ExpectEventCount(1); |
| UpdateSID("120002"); // MVNO matches as well. |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid120002"); |
| EXPECT_EQ("120002", operator_info_->sid()); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, InternationalMVNOMatch) { |
| // message: international MVNO (imsi filter). |
| // match by: MNO matches by MCCMNC, |
| // MVNO matches by IMSI after first IMSI update, |
| // MVNO matches again after MCCMNC change. |
| // verify: Three Observer events: MNO followed by MVNO twice. |
| ExpectEventCount(1); |
| UpdateMCCMNC("127001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid127001"); |
| |
| ExpectEventCount(1); |
| UpdateIMSI("1270015432154322"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid127001-mvno"); |
| |
| ExpectEventCount(1); |
| UpdateMCCMNC("118001"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid127001-mvno"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MVNOAllMatch) { |
| // message: MNO with following MVNOS: |
| // - one with no filter. |
| // - one with name filter. |
| // - one with imsi filter. |
| // - one with iccid filter. |
| // - one with name and iccid filter. |
| // verify: |
| // - initial MCCMNC matches the default MVNO directly (not MNO) |
| // - match each of the MVNOs in turn. |
| // - give super set information that does not match any MVNO correctly, |
| // verify that the MNO matches. |
| ExpectEventCount(1); |
| UpdateMCCMNC("121001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid121001"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(2); |
| UpdateMCCMNC("121001"); |
| UpdateOperatorName("name121003"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid121003"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(2); |
| UpdateMCCMNC("121001"); |
| UpdateIMSI("1210045432154321"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid121004"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(2); |
| UpdateMCCMNC("121001"); |
| UpdateICCID("121005123456789"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid121005"); |
| |
| ResetOperatorInfo(); |
| ExpectEventCount(3); |
| UpdateMCCMNC("121001"); |
| UpdateOperatorName("name121006"); |
| VerifyMNOWithUUID("uuid121001"); |
| UpdateICCID("121006123456789"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid121006"); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MVNOMatchAndMismatch) { |
| // message: MNO with one MVNO with name filter. |
| // match by: MNO matches by MCCMNC |
| // MVNO matches by name. |
| // Second name update causes the MVNO to not match again. |
| ExpectEventCount(1); |
| UpdateMCCMNC("113001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid113001"); |
| |
| ExpectEventCount(1); |
| UpdateOperatorName("name113002"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid113002"); |
| EXPECT_EQ("name113002", operator_info_->operator_name()); |
| |
| ExpectEventCount(1); |
| UpdateOperatorName("name113999"); // No match. |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid113001"); |
| // User operator name is given preference. |
| EXPECT_EQ("name113999", operator_info_->operator_name()); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MVNOMatchAndReset) { |
| // message: MVNO with name filter. |
| // verify; |
| // - match MVNO by name. |
| // - Reset object, verify Observer event, and not match. |
| // - match MVNO by name again. |
| ExpectEventCount(1); |
| UpdateMCCMNC("113001"); |
| VerifyEventCount(); |
| ExpectEventCount(1); |
| VerifyMNOWithUUID("uuid113001"); |
| UpdateOperatorName("name113002"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid113002"); |
| EXPECT_EQ("name113002", operator_info_->operator_name()); |
| |
| ExpectEventCount(1); |
| operator_info_->Reset(); |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| |
| ExpectEventCount(1); |
| UpdateMCCMNC("113001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid113001"); |
| ExpectEventCount(1); |
| UpdateOperatorName("name113002"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid113002"); |
| EXPECT_EQ("name113002", operator_info_->operator_name()); |
| } |
| |
| // Here, we rely on our knowledge about the implementation: The SID and MCCMNC |
| // updates follow the same code paths, and so we can get away with not testing |
| // all the scenarios we test above for MCCMNC. Instead, we only do basic testing |
| // to make sure that SID upates operator as MCCMNC updates do. |
| TEST_P(MobileOperatorInfoMainTest, MNOBySID) { |
| // message: Has an MNO with no MVNO. |
| // match by: SID. |
| // verify: Observer event, uuid. |
| |
| ExpectEventCount(0); |
| UpdateSID("1229"); // No match. |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| |
| ExpectEventCount(1); |
| UpdateSID("1221"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid1221"); |
| |
| ExpectEventCount(1); |
| UpdateSID("1229"); // No Match. |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| } |
| |
| TEST_P(MobileOperatorInfoMainTest, MNOByMCCMNCAndSID) { |
| // message: Has an MNO with no MVNO. |
| // match by: SID / MCCMNC alternately. |
| // verify: Observer event, uuid. |
| |
| ExpectEventCount(0); |
| UpdateMCCMNC("123999"); // NO match. |
| UpdateSID("1239"); // No match. |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| |
| ExpectEventCount(1); |
| UpdateMCCMNC("123001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid123001"); |
| |
| ExpectEventCount(1); |
| operator_info_->Reset(); |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| |
| ExpectEventCount(1); |
| UpdateSID("1232"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid1232"); |
| |
| ExpectEventCount(1); |
| operator_info_->Reset(); |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| |
| ExpectEventCount(1); |
| UpdateMCCMNC("123001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid123001"); |
| } |
| |
| class MobileOperatorInfoDataTest : public MobileOperatorInfoMainTest { |
| public: |
| MobileOperatorInfoDataTest() = default; |
| MobileOperatorInfoDataTest(const MobileOperatorInfoDataTest&) = delete; |
| MobileOperatorInfoDataTest& operator=(const MobileOperatorInfoDataTest&) = |
| delete; |
| |
| // Same as MobileOperatorInfoMainTest, except that the database used is |
| // different. |
| void SetUp() override { |
| EXPECT_TRUE(SetUpDatabase({"data_test.pbf"})); |
| operator_info_->AddObserver(&observer_); |
| } |
| |
| protected: |
| // This is a function that does a best effort verification of the information |
| // that is obtained from the database by the MobileOperatorInfo object against |
| // expectations stored in the form of data members in this class. |
| // This is not a full proof check. In particular: |
| // - It is unspecified in some case which of the values from a list is |
| // exposed as a property. For example, at best, we can check that |sid| is |
| // non-empty. |
| // - It is not robust to "" as property values at times. |
| void VerifyDatabaseData() { |
| EXPECT_EQ(country_, operator_info_->country()); |
| EXPECT_EQ(requires_roaming_, operator_info_->requires_roaming()); |
| EXPECT_EQ(mtu_, operator_info_->mtu()); |
| EXPECT_EQ(activation_code_, operator_info_->activation_code()); |
| |
| EXPECT_EQ(mccmnc_list_.size(), operator_info_->mccmnc_list().size()); |
| std::set<std::string> mccmnc_set(operator_info_->mccmnc_list().begin(), |
| operator_info_->mccmnc_list().end()); |
| for (const auto& mccmnc : mccmnc_list_) { |
| EXPECT_TRUE(mccmnc_set.find(mccmnc) != mccmnc_set.end()); |
| } |
| if (!mccmnc_list_.empty()) { |
| // It is not specified which entry will be chosen, but mccmnc() must be |
| // non empty. |
| EXPECT_FALSE(operator_info_->mccmnc().empty()); |
| } |
| |
| VerifyNameListsMatch(operator_name_list_, |
| operator_info_->operator_name_list()); |
| |
| // This comparison breaks if two apns have the same |apn| field. |
| EXPECT_EQ(apn_list_.size(), operator_info_->apn_list().size()); |
| std::map<std::string, const MobileOperatorInfo::MobileAPN*> mobile_apns; |
| for (const auto& apn_node : operator_info_->apn_list()) { |
| mobile_apns[apn_node->apn] = apn_node.get(); |
| } |
| for (const auto& apn_lhs : apn_list_) { |
| ASSERT_TRUE(mobile_apns.find(apn_lhs->apn) != mobile_apns.end()); |
| const auto& apn_rhs = mobile_apns[apn_lhs->apn]; |
| // Only comparing apn, name, username, password. |
| EXPECT_EQ(apn_lhs->apn, apn_rhs->apn); |
| EXPECT_EQ(apn_lhs->username, apn_rhs->username); |
| EXPECT_EQ(apn_lhs->password, apn_rhs->password); |
| VerifyNameListsMatch(apn_lhs->operator_name_list, |
| apn_rhs->operator_name_list); |
| } |
| |
| EXPECT_EQ(olp_list_.size(), operator_info_->olp_list().size()); |
| // This comparison breaks if two OLPs have the same |url|. |
| std::map<std::string, MobileOperatorInfo::OnlinePortal> olps; |
| for (const auto& olp : operator_info_->olp_list()) { |
| olps[olp.url] = olp; |
| } |
| for (const auto& olp : olp_list_) { |
| ASSERT_TRUE(olps.find(olp.url) != olps.end()); |
| const auto& olp_rhs = olps[olp.url]; |
| EXPECT_EQ(olp.method, olp_rhs.method); |
| EXPECT_EQ(olp.post_data, olp_rhs.post_data); |
| } |
| |
| EXPECT_EQ(sid_list_.size(), operator_info_->sid_list().size()); |
| std::set<std::string> sid_set(operator_info_->sid_list().begin(), |
| operator_info_->sid_list().end()); |
| for (const auto& sid : sid_list_) { |
| EXPECT_TRUE(sid_set.find(sid) != sid_set.end()); |
| } |
| if (!sid_list_.empty()) { |
| // It is not specified which entry will be chosen, but |sid()| must be |
| // non-empty. |
| EXPECT_FALSE(operator_info_->sid().empty()); |
| } |
| } |
| |
| // This function does some extra checks for the user data that can not be done |
| // when data is obtained from the database. |
| void VerifyUserData() { EXPECT_EQ(sid_, operator_info_->sid()); } |
| |
| void VerifyNameListsMatch( |
| const std::vector<MobileOperatorInfo::LocalizedName>& |
| operator_name_list_lhs, |
| const std::vector<MobileOperatorInfo::LocalizedName>& |
| operator_name_list_rhs) { |
| // This comparison breaks if two localized names have the same |name|. |
| std::map<std::string, MobileOperatorInfo::LocalizedName> localized_names; |
| for (const auto& localized_name : operator_name_list_rhs) { |
| localized_names[localized_name.name] = localized_name; |
| } |
| for (const auto& localized_name : operator_name_list_lhs) { |
| EXPECT_TRUE(localized_names.find(localized_name.name) != |
| localized_names.end()); |
| EXPECT_EQ(localized_name.language, |
| localized_names[localized_name.name].language); |
| } |
| } |
| |
| // Use this function to pre-popluate all the data members of this object with |
| // values matching the MNO for the database in |data_test.prototxt|. |
| void PopulateMNOData() { |
| country_ = "us"; |
| requires_roaming_ = true; |
| mtu_ = 1400; |
| activation_code_ = "open sesame"; |
| mccmnc_list_ = {"200001", "200002", "200003"}; |
| operator_name_list_ = {{"name200001", "en"}, {"name200002", ""}}; |
| |
| apn_list_.clear(); |
| auto apn = std::make_unique<MobileOperatorInfo::MobileAPN>(); |
| apn->apn = "test@test.com"; |
| apn->username = "testuser"; |
| apn->password = "is_public_boohoohoo"; |
| apn->operator_name_list = {{"name200003", "hi"}}; |
| apn_list_.push_back(std::move(apn)); |
| |
| olp_list_ = {{"some@random.com", "POST", "random_data"}}; |
| sid_list_ = {"200123", "200234", "200345"}; |
| } |
| |
| // Use this function to pre-populate all the data members of this object with |
| // values matching the MVNO for the database in |data_test.prototext|. |
| void PopulateMVNOData() { |
| country_ = "ca"; |
| requires_roaming_ = false; |
| mtu_ = 1200; |
| activation_code_ = "khul ja sim sim"; |
| mccmnc_list_ = {"200001", "200102"}; |
| operator_name_list_ = {{"name200101", "en"}, {"name200102", ""}}; |
| |
| apn_list_.clear(); |
| auto apn = std::make_unique<MobileOperatorInfo::MobileAPN>(); |
| apn->apn = "test2@test.com"; |
| apn->username = "testuser2"; |
| apn->password = "is_public_boohoohoo_too"; |
| apn_list_.push_back(std::move(apn)); |
| |
| olp_list_ = {{"someother@random.com", "GET", ""}}; |
| sid_list_ = {"200345"}; |
| } |
| |
| // Data to be verified against the database. |
| std::string country_; |
| bool requires_roaming_; |
| int32_t mtu_; |
| std::string activation_code_; |
| std::vector<std::string> mccmnc_list_; |
| std::vector<MobileOperatorInfo::LocalizedName> operator_name_list_; |
| std::vector<std::unique_ptr<MobileOperatorInfo::MobileAPN>> apn_list_; |
| std::vector<MobileOperatorInfo::OnlinePortal> olp_list_; |
| std::vector<std::string> sid_list_; |
| |
| // Extra data to be verified only against user updates. |
| std::string sid_; |
| }; |
| |
| TEST_P(MobileOperatorInfoDataTest, MNODetailedInformation) { |
| // message: MNO with all the information filled in. |
| // match by: MNO matches by MCCMNC |
| // verify: All information is correctly loaded. |
| ExpectEventCount(1); |
| UpdateMCCMNC("200001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid200001"); |
| |
| PopulateMNOData(); |
| VerifyDatabaseData(); |
| } |
| |
| TEST_P(MobileOperatorInfoDataTest, MVNOInheritsInformation) { |
| // message: MVNO with name filter. |
| // verify: All the missing fields are carried over to the MVNO from MNO. |
| ExpectEventCount(2); |
| UpdateMCCMNC("200001"); |
| UpdateOperatorName("name200201"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid200201"); |
| |
| PopulateMNOData(); |
| VerifyDatabaseData(); |
| } |
| |
| TEST_P(MobileOperatorInfoDataTest, MVNOOverridesInformation) { |
| // match by: MNO matches by MCCMNC, MVNO by name. |
| // verify: All information is correctly loaded. |
| // The MVNO in this case overrides the information provided by MNO. |
| ExpectEventCount(2); |
| UpdateMCCMNC("200001"); |
| UpdateOperatorName("name200101"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid200101"); |
| |
| PopulateMVNOData(); |
| VerifyDatabaseData(); |
| } |
| |
| TEST_P(MobileOperatorInfoDataTest, NoUpdatesBeforeMNOMatch) { |
| // message: MVNO. |
| // - do not match MNO with mccmnc/name |
| // - on different updates, verify no events. |
| ExpectEventCount(0); |
| UpdateMCCMNC("200999"); // No match. |
| UpdateOperatorName("name200001"); // matches MNO |
| UpdateOperatorName("name200101"); // matches MVNO filter. |
| UpdateSID("200999"); // No match. |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| } |
| |
| TEST_P(MobileOperatorInfoDataTest, UserUpdatesOverrideMVNO) { |
| // - match MVNO. |
| // - send updates to properties and verify events are raised and values of |
| // updated properties override the ones provided by the database. |
| std::string imsi{"2009991234512345"}; |
| std::string iccid{"200999123456789"}; |
| std::string olp_url{"url@url.com"}; |
| std::string olp_method{"POST"}; |
| std::string olp_post_data{"data"}; |
| |
| // Determine MVNO. |
| ExpectEventCount(2); |
| UpdateMCCMNC("200001"); |
| UpdateOperatorName("name200101"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid200101"); |
| |
| // Send updates. |
| ExpectEventCount(1); |
| UpdateOnlinePortal(olp_url, olp_method, olp_post_data); |
| UpdateIMSI(imsi); |
| // No event raised because imsi is not exposed. |
| UpdateICCID(iccid); |
| // No event raised because ICCID is not exposed. |
| |
| VerifyEventCount(); |
| |
| // Update our expectations. |
| PopulateMVNOData(); |
| olp_list_.push_back({olp_url, olp_method, olp_post_data}); |
| |
| VerifyDatabaseData(); |
| } |
| |
| TEST_P(MobileOperatorInfoDataTest, CachedUserUpdatesOverrideMVNO) { |
| // message: MVNO. |
| // - First send updates that don't identify an MNO. |
| // - Then identify an MNO and MVNO. |
| // - verify that all the earlier updates are cached, and override the MVNO |
| // information. |
| std::string imsi{"2009991234512345"}; |
| std::string iccid{"200999123456789"}; |
| std::string sid{"200999"}; |
| std::string olp_url{"url@url.com"}; |
| std::string olp_method{"POST"}; |
| std::string olp_post_data{"data"}; |
| |
| // Send updates. |
| ExpectEventCount(0); |
| UpdateSID(sid); |
| UpdateOnlinePortal(olp_url, olp_method, olp_post_data); |
| UpdateIMSI(imsi); |
| UpdateICCID(iccid); |
| VerifyEventCount(); |
| |
| // Determine MVNO. |
| ExpectEventCount(2); |
| UpdateMCCMNC("200001"); |
| UpdateOperatorName("name200101"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid200101"); |
| |
| // Update our expectations. |
| PopulateMVNOData(); |
| sid_ = sid; |
| sid_list_.push_back(sid); |
| olp_list_.push_back({olp_url, olp_method, olp_post_data}); |
| |
| VerifyDatabaseData(); |
| VerifyUserData(); |
| } |
| |
| TEST_P(MobileOperatorInfoDataTest, RedundantUserUpdatesMVNO) { |
| // - match MVNO. |
| // - send redundant updates to properties. |
| // - Verify no events, no updates to properties. |
| |
| // Identify MVNO. |
| ExpectEventCount(2); |
| UpdateMCCMNC("200001"); |
| UpdateOperatorName("name200101"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid200101"); |
| |
| // Send redundant updates. |
| // TODO(pprabhu) |
| // |UpdateOnlinePortal| leads to an event because this is the first time this |
| // value are set *by the user*. Although the values from the database were the |
| // same, we did not use those values for filters. It would be ideal to not |
| // raise these redundant events (since no public information about the object |
| // changed), but I haven't invested in doing so yet. |
| ExpectEventCount(1); |
| UpdateOperatorName(operator_info_->operator_name()); |
| UpdateOnlinePortal("someother@random.com", "GET", ""); |
| VerifyEventCount(); |
| PopulateMVNOData(); |
| VerifyDatabaseData(); |
| } |
| |
| TEST_P(MobileOperatorInfoDataTest, RedundantCachedUpdatesMVNO) { |
| // message: MVNO. |
| // - First send updates that don't identify MVNO, but match the data. |
| // - Then idenityf an MNO and MVNO. |
| // - verify that redundant information occurs only once. |
| |
| // Send redundant updates. |
| ExpectEventCount(2); |
| UpdateSID(operator_info_->sid()); |
| UpdateOperatorName(operator_info_->operator_name()); |
| UpdateOnlinePortal("someother@random.com", "GET", ""); |
| |
| // Identify MVNO. |
| UpdateMCCMNC("200001"); |
| UpdateOperatorName("name200101"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid200101"); |
| |
| PopulateMVNOData(); |
| VerifyDatabaseData(); |
| } |
| |
| TEST_P(MobileOperatorInfoDataTest, ResetClearsInformation) { |
| // Repeatedly reset the object and check M[V]NO identification and data. |
| ExpectEventCount(2); |
| UpdateMCCMNC("200001"); |
| UpdateOperatorName("name200201"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid200201"); |
| PopulateMNOData(); |
| VerifyDatabaseData(); |
| |
| ExpectEventCount(1); |
| operator_info_->Reset(); |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| |
| ExpectEventCount(2); |
| UpdateMCCMNC("200001"); |
| UpdateOperatorName("name200101"); |
| VerifyEventCount(); |
| VerifyMVNOWithUUID("uuid200101"); |
| PopulateMVNOData(); |
| VerifyDatabaseData(); |
| |
| ExpectEventCount(1); |
| operator_info_->Reset(); |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| |
| ExpectEventCount(1); |
| UpdateMCCMNC("200001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid200001"); |
| PopulateMNOData(); |
| VerifyDatabaseData(); |
| } |
| |
| TEST_P(MobileOperatorInfoDataTest, FilteredOLP) { |
| // We only check basic filter matching, using the fact that the regex matching |
| // code is shared with the MVNO filtering, and is already well tested. |
| // (1) None of the filters match. |
| ExpectEventCount(1); |
| UpdateMCCMNC("200001"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid200001"); |
| |
| ASSERT_EQ(1, operator_info_->olp_list().size()); |
| // Just check that the filtered OLPs are not in the list. |
| EXPECT_NE("olp@mccmnc", operator_info_->olp_list()[0].url); |
| EXPECT_NE("olp@sid", operator_info_->olp_list()[0].url); |
| |
| // (2) MCCMNC filter matches. |
| ExpectEventCount(1); |
| operator_info_->Reset(); |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| |
| ExpectEventCount(1); |
| UpdateMCCMNC("200003"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid200001"); |
| |
| ASSERT_EQ(2, operator_info_->olp_list().size()); |
| EXPECT_NE("olp@sid", operator_info_->olp_list()[0].url); |
| bool found_olp_by_mccmnc = false; |
| for (const auto& olp : operator_info_->olp_list()) { |
| found_olp_by_mccmnc |= ("olp@mccmnc" == olp.url); |
| } |
| EXPECT_TRUE(found_olp_by_mccmnc); |
| |
| // (3) SID filter matches. |
| ExpectEventCount(1); |
| operator_info_->Reset(); |
| VerifyEventCount(); |
| VerifyNoMatch(); |
| |
| ExpectEventCount(1); |
| UpdateSID("200345"); |
| VerifyEventCount(); |
| VerifyMNOWithUUID("uuid200001"); |
| |
| ASSERT_EQ(2, operator_info_->olp_list().size()); |
| EXPECT_NE("olp@mccmnc", operator_info_->olp_list()[0].url); |
| bool found_olp_by_sid = false; |
| for (const auto& olp : operator_info_->olp_list()) { |
| found_olp_by_sid |= ("olp@sid" == olp.url); |
| } |
| EXPECT_TRUE(found_olp_by_sid); |
| } |
| |
| class MobileOperatorInfoObserverTest : public MobileOperatorInfoMainTest { |
| public: |
| MobileOperatorInfoObserverTest() = default; |
| MobileOperatorInfoObserverTest(const MobileOperatorInfoObserverTest&) = |
| delete; |
| MobileOperatorInfoObserverTest& operator=( |
| const MobileOperatorInfoObserverTest&) = delete; |
| |
| // Same as |MobileOperatorInfoMainTest::SetUp|, except that we don't add a |
| // default observer. |
| void SetUp() override { EXPECT_TRUE(SetUpDatabase({"data_test.pbf"})); } |
| |
| protected: |
| // /////////////////////////////////////////////////////////////////////////// |
| // Data. |
| MockMobileOperatorInfoObserver second_observer_; |
| }; |
| |
| TEST_P(MobileOperatorInfoObserverTest, NoObserver) { |
| // - Don't add any observers, and then cause an MVNO update to occur. |
| // - Verify no crash. |
| UpdateMCCMNC("200001"); |
| UpdateOperatorName("name200101"); |
| } |
| |
| TEST_P(MobileOperatorInfoObserverTest, MultipleObservers) { |
| // - Add two observers, and then cause an MVNO update to occur. |
| // - Verify both observers are notified. |
| operator_info_->AddObserver(&observer_); |
| operator_info_->AddObserver(&second_observer_); |
| |
| EXPECT_CALL(observer_, OnOperatorChanged()).Times(2); |
| EXPECT_CALL(second_observer_, OnOperatorChanged()).Times(2); |
| UpdateMCCMNC("200001"); |
| UpdateOperatorName("name200101"); |
| VerifyMVNOWithUUID("uuid200101"); |
| |
| dispatcher_.DispatchPendingEvents(); |
| } |
| |
| TEST_P(MobileOperatorInfoObserverTest, LateObserver) { |
| // - Add one observer, and verify it gets an MVNO update. |
| operator_info_->AddObserver(&observer_); |
| |
| EXPECT_CALL(observer_, OnOperatorChanged()).Times(2); |
| EXPECT_CALL(second_observer_, OnOperatorChanged()).Times(0); |
| UpdateMCCMNC("200001"); |
| UpdateOperatorName("name200101"); |
| VerifyMVNOWithUUID("uuid200101"); |
| dispatcher_.DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&observer_); |
| Mock::VerifyAndClearExpectations(&second_observer_); |
| |
| EXPECT_CALL(observer_, OnOperatorChanged()).Times(1); |
| EXPECT_CALL(second_observer_, OnOperatorChanged()).Times(0); |
| operator_info_->Reset(); |
| VerifyNoMatch(); |
| dispatcher_.DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&observer_); |
| Mock::VerifyAndClearExpectations(&second_observer_); |
| |
| // - Add another observer, verify both get an MVNO update. |
| operator_info_->AddObserver(&second_observer_); |
| |
| EXPECT_CALL(observer_, OnOperatorChanged()).Times(2); |
| EXPECT_CALL(second_observer_, OnOperatorChanged()).Times(2); |
| UpdateMCCMNC("200001"); |
| UpdateOperatorName("name200101"); |
| VerifyMVNOWithUUID("uuid200101"); |
| dispatcher_.DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&observer_); |
| Mock::VerifyAndClearExpectations(&second_observer_); |
| |
| EXPECT_CALL(observer_, OnOperatorChanged()).Times(1); |
| EXPECT_CALL(second_observer_, OnOperatorChanged()).Times(1); |
| operator_info_->Reset(); |
| VerifyNoMatch(); |
| dispatcher_.DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&observer_); |
| Mock::VerifyAndClearExpectations(&second_observer_); |
| |
| // - Remove an observer, verify it no longer gets updates. |
| operator_info_->RemoveObserver(&observer_); |
| |
| EXPECT_CALL(observer_, OnOperatorChanged()).Times(0); |
| EXPECT_CALL(second_observer_, OnOperatorChanged()).Times(2); |
| UpdateMCCMNC("200001"); |
| UpdateOperatorName("name200101"); |
| VerifyMVNOWithUUID("uuid200101"); |
| dispatcher_.DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&observer_); |
| Mock::VerifyAndClearExpectations(&second_observer_); |
| |
| EXPECT_CALL(observer_, OnOperatorChanged()).Times(0); |
| EXPECT_CALL(second_observer_, OnOperatorChanged()).Times(1); |
| operator_info_->Reset(); |
| VerifyNoMatch(); |
| dispatcher_.DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&observer_); |
| Mock::VerifyAndClearExpectations(&second_observer_); |
| } |
| |
| class MobileOperatorInfoOverrideTest |
| : public ::testing::TestWithParam< |
| std::vector<std::pair<std::string, std::string>>> { |
| public: |
| MobileOperatorInfoOverrideTest() |
| : operator_info_impl_(new MobileOperatorInfoImpl( |
| &dispatcher_, |
| "Operator", |
| GetTestProtoPath("init_test_override_db_init_1.pbf"), |
| GetTestProtoPath("init_test_override_db_init_2.pbf"))) {} |
| |
| void SetUp() override { EXPECT_TRUE(operator_info_impl_->Init()); } |
| |
| protected: |
| void VerifyAPNForMCCMNC(const std::string& mccmnc, const std::string& apn) { |
| UpdateMCCMNC(mccmnc); |
| EXPECT_TRUE(operator_info_impl_->IsMobileNetworkOperatorKnown()); |
| EXPECT_FALSE(operator_info_impl_->IsMobileVirtualNetworkOperatorKnown()); |
| std::map<std::string, const MobileOperatorInfo::MobileAPN*> mobile_apns; |
| |
| bool found_apn = false; |
| for (const auto& apn_node : operator_info_impl_->apn_list()) { |
| if (apn_node->apn == apn) { |
| found_apn = true; |
| break; |
| } |
| } |
| ASSERT_TRUE(found_apn); |
| } |
| |
| void UpdateMCCMNC(const std::string& mccmnc) { |
| operator_info_impl_->UpdateMCCMNC(mccmnc); |
| } |
| |
| EventDispatcherForTest dispatcher_; |
| std::unique_ptr<MobileOperatorInfoImpl> operator_info_impl_; |
| }; |
| |
| // Prevent regression of database override behavior introduced in |
| // chromium:654149 |
| TEST_P(MobileOperatorInfoOverrideTest, MultipleDBOverrides) { |
| for (const auto& mcc_apn_pair : GetParam()) { |
| VerifyAPNForMCCMNC(mcc_apn_pair.first, mcc_apn_pair.second); |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(MobileOperatorInfoMainTestInstance, |
| MobileOperatorInfoMainTest, |
| Values(kEventCheckingPolicyStrict, |
| kEventCheckingPolicyNonStrict)); |
| INSTANTIATE_TEST_SUITE_P(MobileOperatorInfoDataTestInstance, |
| MobileOperatorInfoDataTest, |
| Values(kEventCheckingPolicyStrict, |
| kEventCheckingPolicyNonStrict)); |
| // It only makes sense to do strict checking here. |
| INSTANTIATE_TEST_SUITE_P(MobileOperatorInfoObserverTestInstance, |
| MobileOperatorInfoObserverTest, |
| Values(kEventCheckingPolicyStrict)); |
| |
| std::vector<std::pair<std::string, std::string>> kMccmncApnPairs = { |
| {"00", "zeroes_override"}, {"00", "twosies_override"}, |
| {"01", "zeros_default"}, {"01", "onesies_default"}, |
| {"02", "zeroes_override"}, {"02", "twosies_override"}}; |
| |
| INSTANTIATE_TEST_SUITE_P(MobileOperatorInfoOverrideTestInstance, |
| MobileOperatorInfoOverrideTest, |
| Values(kMccmncApnPairs)); |
| } // namespace shill |