//
// Copyright (C) 2014 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.
//
#include "shill/cellular/mobile_operator_info.h"
#include <fstream>
#include <map>
#include <ostream>
#include <set>
#include <vector>
#include <base/files/file_util.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"
// These files contain binary protobuf definitions used by the following tests
// inside the namespace ::mobile_operator_db
#define IN_MOBILE_OPERATOR_INFO_UNITTEST_CC
#include "shill/mobile_operator_db/test_protos/data_test.h"
#include "shill/mobile_operator_db/test_protos/init_test_empty_db_init.h"
#include "shill/mobile_operator_db/test_protos/init_test_multiple_db_init_1.h"
#include "shill/mobile_operator_db/test_protos/init_test_multiple_db_init_2.h"
#include "shill/mobile_operator_db/test_protos/init_test_successful_init.h"
#include "shill/mobile_operator_db/test_protos/main_test.h"
#undef IN_MOBILE_OPERATOR_INFO_UNITTEST_CC
using base::FilePath;
using shill::mobile_operator_db::MobileOperatorDB;
using std::map;
using std::ofstream;
using std::set;
using std::string;
using std::vector;
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
};
} // namespace
class MockMobileOperatorInfoObserver : public MobileOperatorInfo::Observer {
public:
MockMobileOperatorInfoObserver() {}
virtual ~MockMobileOperatorInfoObserver() {}
MOCK_METHOD0(OnOperatorChanged, void());
};
class MobileOperatorInfoInitTest : public Test {
public:
MobileOperatorInfoInitTest()
: operator_info_(new MobileOperatorInfo(&dispatcher_, "Operator")),
operator_info_impl_(operator_info_->impl()) {}
void TearDown() override {
for (const auto& tmp_db_path : tmp_db_paths_) {
base::DeleteFile(tmp_db_path, false);
}
}
protected:
void AddDatabase(const unsigned char database_data[], size_t num_elems) {
FilePath tmp_db_path;
CHECK(base::CreateTemporaryFile(&tmp_db_path));
tmp_db_paths_.push_back(tmp_db_path);
ofstream tmp_db(tmp_db_path.value(), ofstream::binary);
for (size_t i = 0; i < num_elems; ++i) {
tmp_db << database_data[i];
}
tmp_db.close();
operator_info_->AddDatabasePath(tmp_db_path);
}
void AssertDatabaseEmpty() {
EXPECT_EQ(0, operator_info_impl_->database()->mno_size());
EXPECT_EQ(0, operator_info_impl_->database()->imvno_size());
}
const MobileOperatorDB* GetDatabase() {
return operator_info_impl_->database();
}
EventDispatcherForTest dispatcher_;
vector<FilePath> tmp_db_paths_;
std::unique_ptr<MobileOperatorInfo> operator_info_;
// Owned by |operator_info_| and tied to its life cycle.
MobileOperatorInfoImpl* operator_info_impl_;
private:
DISALLOW_COPY_AND_ASSIGN(MobileOperatorInfoInitTest);
};
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.
const FilePath database_path("nonexistent.pbf");
operator_info_->ClearDatabasePaths();
operator_info_->AddDatabasePath(database_path);
EXPECT_FALSE(operator_info_->Init());
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.
operator_info_->ClearDatabasePaths();
// Can't use arraysize on empty array.
AddDatabase(mobile_operator_db::init_test_empty_db_init, 0);
EXPECT_TRUE(operator_info_->Init());
AssertDatabaseEmpty();
}
TEST_F(MobileOperatorInfoInitTest, SuccessfulInit) {
operator_info_->ClearDatabasePaths();
AddDatabase(mobile_operator_db::init_test_successful_init,
arraysize(mobile_operator_db::init_test_successful_init));
EXPECT_TRUE(operator_info_->Init());
EXPECT_GT(GetDatabase()->mno_size(), 0);
EXPECT_GT(GetDatabase()->imvno_size(), 0);
}
TEST_F(MobileOperatorInfoInitTest, MultipleDBInit) {
// - Initialize the object with two database files.
// - Verify that intialization succeeds, and both databases are loaded.
operator_info_->ClearDatabasePaths();
AddDatabase(mobile_operator_db::init_test_multiple_db_init_1,
arraysize(mobile_operator_db::init_test_multiple_db_init_1));
AddDatabase(mobile_operator_db::init_test_multiple_db_init_2,
arraysize(mobile_operator_db::init_test_multiple_db_init_2));
operator_info_->Init();
EXPECT_GT(GetDatabase()->mno_size(), 0);
EXPECT_GT(GetDatabase()->imvno_size(), 0);
}
TEST_F(MobileOperatorInfoInitTest, InitWithObserver) {
// - Add an Observer.
// - Initialize the object with empty database file.
// - Verify innitialization succeeds.
MockMobileOperatorInfoObserver dumb_observer;
operator_info_->ClearDatabasePaths();
// Can't use arraysize with empty array.
AddDatabase(mobile_operator_db::init_test_empty_db_init, 0);
operator_info_->AddObserver(&dumb_observer);
EXPECT_TRUE(operator_info_->Init());
}
class MobileOperatorInfoMainTest
: public MobileOperatorInfoInitTest,
public WithParamInterface<EventCheckingPolicy> {
public:
MobileOperatorInfoMainTest()
: MobileOperatorInfoInitTest(),
event_checking_policy_(GetParam()) {}
virtual void SetUp() {
operator_info_->ClearDatabasePaths();
AddDatabase(mobile_operator_db::main_test,
arraysize(mobile_operator_db::main_test));
operator_info_->Init();
operator_info_->AddObserver(&observer_);
}
protected:
// ///////////////////////////////////////////////////////////////////////////
// Helper functions.
void VerifyMNOWithUUID(const string& uuid) {
EXPECT_TRUE(operator_info_->IsMobileNetworkOperatorKnown());
EXPECT_FALSE(operator_info_->IsMobileVirtualNetworkOperatorKnown());
EXPECT_EQ(uuid, operator_info_->uuid());
}
void VerifyMVNOWithUUID(const 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_;
private:
DISALLOW_COPY_AND_ASSIGN(MobileOperatorInfoMainTest);
};
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());
}
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 from the database is given preference over the user supplied
// one.
EXPECT_EQ("name108001", 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");
EXPECT_EQ("name108002", 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");
// Name from the database is given preference.
EXPECT_EQ("name113001", 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.
ExpectEventCount(1);
UpdateMCCMNC("118001");
VerifyEventCount();
VerifyMNOWithUUID("uuid118001");
ExpectEventCount(0);
UpdateIMSI("1180011234512345"); // No match.
VerifyEventCount();
VerifyMNOWithUUID("uuid118001");
ExpectEventCount(1);
UpdateIMSI("1180015432154321");
VerifyEventCount();
VerifyMVNOWithUUID("uuid118002");
}
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, 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");
// Name from database is given preference.
EXPECT_EQ("name113001", 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() : MobileOperatorInfoMainTest() {}
// Same as MobileOperatorInfoMainTest, except that the database used is
// different.
virtual void SetUp() {
operator_info_->ClearDatabasePaths();
AddDatabase(mobile_operator_db::data_test,
arraysize(mobile_operator_db::data_test));
operator_info_->Init();
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(activation_code_, operator_info_->activation_code());
EXPECT_EQ(mccmnc_list_.size(), operator_info_->mccmnc_list().size());
set<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_.size() > 0) {
// 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());
map<string, const MobileOperatorInfo::MobileAPN*> mobile_apns;
for (const auto& apn_node : operator_info_->apn_list()) {
mobile_apns[apn_node->apn] = apn_node;
}
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|.
map<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());
set<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_.size() > 0) {
// 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 vector<MobileOperatorInfo::LocalizedName>& operator_name_list_lhs,
const vector<MobileOperatorInfo::LocalizedName>& operator_name_list_rhs) {
// This comparison breaks if two localized names have the same |name|.
map<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;
activation_code_ = "open sesame";
mccmnc_list_.clear();
mccmnc_list_.push_back("200001");
mccmnc_list_.push_back("200002");
mccmnc_list_.push_back("200003");
operator_name_list_.clear();
operator_name_list_.push_back({"name200001", "en"});
operator_name_list_.push_back({"name200002", ""});
apn_list_.clear();
MobileOperatorInfo::MobileAPN* apn;
apn = new MobileOperatorInfo::MobileAPN();
apn->apn = "test@test.com";
apn->username = "testuser";
apn->password = "is_public_boohoohoo";
apn->operator_name_list.push_back({"name200003", "hi"});
apn_list_.push_back(apn); // Takes ownership.
olp_list_.clear();
olp_list_.push_back({"some@random.com", "POST", "random_data"});
sid_list_.clear();
sid_list_.push_back("200123");
sid_list_.push_back("200234");
sid_list_.push_back("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;
activation_code_ = "khul ja sim sim";
mccmnc_list_.clear();
mccmnc_list_.push_back("200001");
mccmnc_list_.push_back("200102");
operator_name_list_.clear();
operator_name_list_.push_back({"name200101", "en"});
operator_name_list_.push_back({"name200102", ""});
apn_list_.clear();
MobileOperatorInfo::MobileAPN* apn;
apn = new MobileOperatorInfo::MobileAPN();
apn->apn = "test2@test.com";
apn->username = "testuser2";
apn->password = "is_public_boohoohoo_too";
apn_list_.push_back(apn); // Takes ownership.
olp_list_.clear();
olp_list_.push_back({"someother@random.com", "GET", ""});
sid_list_.clear();
sid_list_.push_back("200345");
}
// Data to be verified against the database.
string country_;
bool requires_roaming_;
string activation_code_;
vector<string> mccmnc_list_;
vector<MobileOperatorInfo::LocalizedName> operator_name_list_;
ScopedVector<MobileOperatorInfo::MobileAPN> apn_list_;
vector<MobileOperatorInfo::OnlinePortal> olp_list_;
vector<string> sid_list_;
// Extra data to be verified only against user updates.
string sid_;
private:
DISALLOW_COPY_AND_ASSIGN(MobileOperatorInfoDataTest);
};
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.
string imsi {"2009991234512345"};
string iccid {"200999123456789"};
string olp_url {"url@url.com"};
string olp_method {"POST"};
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.
string imsi {"2009991234512345"};
string iccid {"200999123456789"};
string sid {"200999"};
string olp_url {"url@url.com"};
string olp_method {"POST"};
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() : MobileOperatorInfoMainTest() {}
// Same as |MobileOperatorInfoMainTest::SetUp|, except that we don't add a
// default observer.
virtual void SetUp() {
operator_info_->ClearDatabasePaths();
AddDatabase(mobile_operator_db::data_test,
arraysize(mobile_operator_db::data_test));
operator_info_->Init();
}
protected:
// ///////////////////////////////////////////////////////////////////////////
// Data.
MockMobileOperatorInfoObserver second_observer_;
private:
DISALLOW_COPY_AND_ASSIGN(MobileOperatorInfoObserverTest);
};
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_);
}
INSTANTIATE_TEST_CASE_P(MobileOperatorInfoMainTestInstance,
MobileOperatorInfoMainTest,
Values(kEventCheckingPolicyStrict,
kEventCheckingPolicyNonStrict));
INSTANTIATE_TEST_CASE_P(MobileOperatorInfoDataTestInstance,
MobileOperatorInfoDataTest,
Values(kEventCheckingPolicyStrict,
kEventCheckingPolicyNonStrict));
// It only makes sense to do strict checking here.
INSTANTIATE_TEST_CASE_P(MobileOperatorInfoObserverTestInstance,
MobileOperatorInfoObserverTest,
Values(kEventCheckingPolicyStrict));
} // namespace shill