shill: Add extended mobile-broadband-provider-info parser to shill.
This CL extends the CellularOperatorInfo class to contain more
mobile-broadband-provider-info data in the following ways:
- data/cellular_operator_info is modified to contain more info than
just OLP. The format has been changed to an extended version of
/usr/share/mobile-broadband-provider-info/serviceproviders.bfd. For
now, it only contains information on one carrier.
- The CellularOperatorInfo class provides the functionality to parse
the contents of the file format described in
data/cellular_operator_info. It provides the functionalities of the
parser in third_party/mobile-broadband-provider-info/src/
(implemented in C) in C++, by exposing similar content in the form
of CellularOperatorInfo::CellularOperator.
- Similar to third_party/mobile-broadband-provider-info/src/,
CellularOperatorInfo can be used to look up a cellular carrier by
name, MCCMNC, but also SID. The output, in addition, contains data
regarding OLP.
BUG=chromium-os:37670
TEST=Build and run unittests.
Change-Id: I4975c79c828d6386517c5c91c1ce9567cd063a15
Reviewed-on: https://gerrit.chromium.org/gerrit/41101
Reviewed-by: Ben Chan <benchan@chromium.org>
Commit-Queue: Arman Uguray <armansito@chromium.org>
Tested-by: Arman Uguray <armansito@chromium.org>
diff --git a/Makefile b/Makefile
index 07a15c6..7835d1d 100644
--- a/Makefile
+++ b/Makefile
@@ -208,6 +208,8 @@
ethernet.o \
ethernet_service.o \
event_dispatcher.o \
+ file_reader.o \
+ file_reader_unittest.o \
geolocation_info.o \
glib.o \
glib_io_ready_handler.o \
diff --git a/cellular_capability_universal.cc b/cellular_capability_universal.cc
index 29c7cc2..9bbbef2 100644
--- a/cellular_capability_universal.cc
+++ b/cellular_capability_universal.cc
@@ -578,10 +578,13 @@
if (!cellular()->cellular_operator_info())
return;
- CellularService::OLP olp;
- if (!cellular()->cellular_operator_info()->GetOLP(operator_id_, &olp))
+ const CellularService::OLP *result =
+ cellular()->cellular_operator_info()->GetOLPByMCCMNC(operator_id_);
+ if (!result)
return;
+ CellularService::OLP olp;
+ olp.CopyFrom(*result);
string post_data = olp.GetPostData();
ReplaceSubstringsAfterOffset(&post_data, 0, "${esn}", esn_);
ReplaceSubstringsAfterOffset(&post_data, 0, "${iccid}", sim_identifier_);
@@ -732,8 +735,9 @@
if (!cellular()->cellular_operator_info())
return false;
- CellularService::OLP olp;
- if (!cellular()->cellular_operator_info()->GetOLP(operator_id_, &olp))
+ const CellularService::OLP *olp =
+ cellular()->cellular_operator_info()->GetOLPByMCCMNC(operator_id_);
+ if (!olp)
return false;
// To avoid false positives, it's safer to assume the service does not
diff --git a/cellular_capability_universal_unittest.cc b/cellular_capability_universal_unittest.cc
index 8a7ac73..ec592bc 100644
--- a/cellular_capability_universal_unittest.cc
+++ b/cellular_capability_universal_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2013 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.
@@ -66,23 +66,6 @@
apn == expected_apn);
}
-class MockCellularOperatorInfoGetOLPHelper {
- public:
- MockCellularOperatorInfoGetOLPHelper(const CellularService::OLP &olp) {
- olp_.CopyFrom(olp);
- }
-
- ~MockCellularOperatorInfoGetOLPHelper() {}
-
- bool GetOLP(const std::string &operator_id, CellularService::OLP *olp) {
- olp->CopyFrom(olp_);
- return true;
- }
-
- private:
- CellularService::OLP olp_;
-};
-
class CellularCapabilityUniversalTest : public testing::Test {
public:
CellularCapabilityUniversalTest()
@@ -1062,8 +1045,6 @@
test_olp.SetPostData("esn=${esn}&imei=${imei}&imsi=${imsi}&mdn=${mdn}&"
"meid=${meid}&min=${min}&iccid=${iccid}");
- MockCellularOperatorInfoGetOLPHelper get_olp_helper(test_olp);
-
capability_->esn_ = "0";
capability_->imei_ = "1";
capability_->imsi_ = "2";
@@ -1074,9 +1055,9 @@
capability_->operator_id_ = "123456";
cellular_->cellular_operator_info_ = &cellular_operator_info_;
- EXPECT_CALL(cellular_operator_info_, GetOLP(capability_->operator_id_, _))
- .WillRepeatedly(Invoke(&get_olp_helper,
- &MockCellularOperatorInfoGetOLPHelper::GetOLP));
+ EXPECT_CALL(cellular_operator_info_,
+ GetOLPByMCCMNC(capability_->operator_id_))
+ .WillRepeatedly(Return(&test_olp));
SetService();
capability_->UpdateOLP();
@@ -1121,8 +1102,8 @@
// Service activation is not needed
cellular_->cellular_operator_info_ = &cellular_operator_info_;
- EXPECT_CALL(cellular_operator_info_, GetOLP(_, _))
- .WillOnce(Return(false));
+ EXPECT_CALL(cellular_operator_info_, GetOLPByMCCMNC(_))
+ .WillOnce(Return((const CellularService::OLP *)NULL));
capability_->UpdateOperatorInfo();
EXPECT_EQ("", capability_->serving_operator_.GetName());
EXPECT_EQ("", capability_->serving_operator_.GetCountry());
@@ -1131,8 +1112,9 @@
// Service activation is needed
capability_->mdn_ = "0000000000";
cellular_->cellular_operator_info_ = &cellular_operator_info_;
- EXPECT_CALL(cellular_operator_info_, GetOLP(_, _))
- .WillOnce(Return(true));
+ CellularService::OLP olp;
+ EXPECT_CALL(cellular_operator_info_, GetOLPByMCCMNC(_))
+ .WillOnce(Return(&olp));
capability_->UpdateOperatorInfo();
EXPECT_EQ(kOperatorId, capability_->serving_operator_.GetCode());
@@ -1153,8 +1135,9 @@
// Service activation is needed
capability_->mdn_ = "0000000000";
cellular_->cellular_operator_info_ = &cellular_operator_info_;
- EXPECT_CALL(cellular_operator_info_, GetOLP(_, _))
- .WillOnce(Return(true));
+ CellularService::OLP olp;
+ EXPECT_CALL(cellular_operator_info_, GetOLPByMCCMNC(_))
+ .WillOnce(Return(&olp));
EXPECT_EQ("cellular_0123", capability_->CreateFriendlyServiceName());
EXPECT_EQ("0123", capability_->serving_operator_.GetCode());
@@ -1182,9 +1165,10 @@
EXPECT_FALSE(capability_->IsServiceActivationRequired());
cellular_->cellular_operator_info_ = &cellular_operator_info_;
- EXPECT_CALL(cellular_operator_info_, GetOLP(_, _))
- .WillOnce(Return(false))
- .WillRepeatedly(Return(true));
+ CellularService::OLP olp;
+ EXPECT_CALL(cellular_operator_info_, GetOLPByMCCMNC(_))
+ .WillOnce(Return((const CellularService::OLP *)NULL))
+ .WillRepeatedly(Return(&olp));
EXPECT_FALSE(capability_->IsServiceActivationRequired());
capability_->mdn_ = "";
diff --git a/cellular_operator_info.cc b/cellular_operator_info.cc
index ab6f75f..92443b9 100644
--- a/cellular_operator_info.cc
+++ b/cellular_operator_info.cc
@@ -1,10 +1,19 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2013 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_operator_info.h"
+#include <base/string_number_conversions.h>
+#include <base/string_split.h>
+#include <base/string_util.h>
+
+#include "shill/file_reader.h"
+#include "shill/logging.h"
+
+using std::map;
using std::string;
+using std::vector;
namespace shill {
@@ -16,48 +25,407 @@
} // namespace
-CellularOperatorInfo::CellularOperatorInfo(GLib *glib) : info_file_(glib) {}
+CellularOperatorInfo::CellularOperator::CellularOperator()
+ : is_primary_(false),
+ requires_roaming_(false) {}
+CellularOperatorInfo::CellularOperator::~CellularOperator() {}
+CellularOperatorInfo::MobileAPN::MobileAPN() {}
+CellularOperatorInfo::MobileAPN::~MobileAPN() {}
+
+CellularOperatorInfo::CellularOperatorInfo() {}
CellularOperatorInfo::~CellularOperatorInfo() {}
+const ScopedVector<CellularOperatorInfo::CellularOperator> &
+CellularOperatorInfo::operators() const {
+ return operators_;
+}
+
+// static
+string CellularOperatorInfo::FormattedMCCMNC(const string &mccmnc) {
+ return "[MCCMNC=" + mccmnc + "]";
+}
+
+// static
+string CellularOperatorInfo::FormattedSID(const string &sid) {
+ return "[SID=" + sid + "]";
+}
+
+const CellularOperatorInfo::CellularOperator *
+CellularOperatorInfo::GetCellularOperatorByMCCMNC(const string &mccmnc) {
+ LOG(INFO) << __func__ << "(" << FormattedMCCMNC(mccmnc) << ")";
+
+ map<string, CellularOperator *>::const_iterator it =
+ mccmnc_to_operator_.find(mccmnc);
+ if (it == mccmnc_to_operator_.end()) {
+ LOG(ERROR) << "Operator with " << FormattedMCCMNC(mccmnc)
+ << " not found.";
+ return NULL;
+ }
+
+ return it->second;
+}
+
+const CellularOperatorInfo::CellularOperator *
+CellularOperatorInfo::GetCellularOperatorBySID(const string &sid) {
+ LOG(INFO) << __func__ << "(" << FormattedSID(sid) << ")";
+
+ map<string, CellularOperator *>::const_iterator it =
+ sid_to_operator_.find(sid);
+ if (it == sid_to_operator_.end()) {
+ LOG(ERROR) << "Operator with " << FormattedSID(sid) << " not found.";
+ return NULL;
+ }
+
+ return it->second;
+}
+
+const vector<const CellularOperatorInfo::CellularOperator *> *
+CellularOperatorInfo::GetCellularOperatorsByName(const string &name) {
+ LOG(INFO) << __func__ << "(" << name << ")";
+
+ map<string, vector<const CellularOperator *> >::const_iterator it =
+ name_to_operators_.find(name);
+ if (it == name_to_operators_.end()) {
+ LOG(ERROR) << "Given name \"" << name << "\" did not match any operators.";
+ return NULL;
+ }
+
+ return &it->second;
+}
+
+const CellularService::OLP *
+CellularOperatorInfo::GetOLPByMCCMNC(const string &mccmnc) {
+ LOG(INFO) << __func__ << "(" << FormattedMCCMNC(mccmnc) << ")";
+
+ const CellularOperator *provider = GetCellularOperatorByMCCMNC(mccmnc);
+ if (!provider)
+ return NULL;
+
+ map<string, uint32>::const_iterator it =
+ provider->mccmnc_to_olp_idx_.find(mccmnc);
+
+ if (it == provider->mccmnc_to_olp_idx_.end())
+ return NULL;
+
+ uint32 index = it->second;
+ if (index >= provider->olp_list_.size()) {
+ LOG(ERROR) << "Invalid OLP index found for "
+ << FormattedMCCMNC(mccmnc) << ".";
+ return NULL;
+ }
+
+ return provider->olp_list_[index];
+}
+
+const CellularService::OLP *
+CellularOperatorInfo::GetOLPBySID(const string &sid) {
+ LOG(INFO) << __func__ << "(" << FormattedSID(sid) << ")";
+
+ const CellularOperator *provider = GetCellularOperatorBySID(sid);
+ if (!provider)
+ return NULL;
+
+ map<string, uint32>::const_iterator it =
+ provider->sid_to_olp_idx_.find(sid);
+
+ if (it == provider->sid_to_olp_idx_.end())
+ return NULL;
+
+ uint32 index = it->second;
+ if (index >= provider->olp_list_.size()) {
+ LOG(ERROR) << "Invalid OLP index found for " << FormattedSID(sid) << ".";
+ return NULL;
+ }
+
+ return provider->olp_list_[index];
+}
+
+void CellularOperatorInfo::ClearOperators() {
+ operators_.reset();
+ mccmnc_to_operator_.clear();
+ sid_to_operator_.clear();
+ name_to_operators_.clear();
+}
+
+// static
+bool CellularOperatorInfo::ParseKeyValue(const string &line,
+ char key_value_delimiter,
+ std::string *key,
+ std::string *value) {
+ size_t length = line.length();
+ for (size_t i = 0; i < length; ++i) {
+ if (line[i] == key_value_delimiter) {
+ key->assign(line, 0, i);
+ value->assign(line, i + 1, length-i);
+ return true;
+ }
+ }
+ return false;
+}
+
bool CellularOperatorInfo::Load(const FilePath &info_file_path) {
- info_file_.set_path(info_file_path);
- if (!info_file_.Open()) {
- LOG(ERROR) << "Could not open cellular operator info file '"
- << info_file_path.value() << "'.";
+ LOG(INFO) << __func__ << "(" << info_file_path.value() << ")";
+
+ // Clear any previus operators.
+ ClearOperators();
+
+ FileReader file_reader;
+ if (!file_reader.Open(info_file_path)) {
+ LOG(ERROR) << "Could not open operator info file.";
return false;
}
+
+ // See data/cellular_operator_info for the format of file contents.
+
+ ParserState state;
+
+ typedef bool (CellularOperatorInfo::*KeyHandlerFunc)
+ (ParserState *, const string &);
+ map<string, KeyHandlerFunc> key_handler_map;
+ key_handler_map["provider"] = &CellularOperatorInfo::HandleProvider;
+ key_handler_map["mccmnc"] = &CellularOperatorInfo::HandleMCCMNC;
+ key_handler_map["name"] = &CellularOperatorInfo::HandleNameKey;
+ key_handler_map["apn"] = &CellularOperatorInfo::HandleAPN;
+ key_handler_map["sid"] = &CellularOperatorInfo::HandleSID;
+ key_handler_map["olp"] = &CellularOperatorInfo::HandleOLP;
+ key_handler_map["country"] = &CellularOperatorInfo::HandleCountry;
+
+ string line;
+ bool firstline = true;
+ while (file_reader.ReadLine(&line)) {
+ // Skip line comments.
+ TrimWhitespaceASCII(line, TRIM_ALL, &line);
+ if (line[0] == '#' || line.empty())
+ continue;
+
+ // If line consists of a single null character, skip
+ if (line.length() == 1 && line[0] == '\0')
+ continue;
+
+ string key, value;
+ if (!ParseKeyValue(line, ':', &key, &value)) {
+ LOG(ERROR) << "Badly formed line: " << line;
+ return false;
+ }
+
+ if (firstline) {
+ if (key != "serviceproviders") {
+ LOG(ERROR) << "File does not begin with \"serviceproviders\" "
+ << "entry.";
+ return false;
+ }
+ if (value != "3.0") {
+ LOG(ERROR) << "Unrecognized serviceproviders format.";
+ return false;
+ }
+ firstline = false;
+ } else {
+ map<string, KeyHandlerFunc>::iterator it = key_handler_map.find(key);
+ if (it == key_handler_map.end()) {
+ LOG(ERROR) << "Invalid key \"" << key << "\".";
+ return false;
+ }
+ KeyHandlerFunc func = it->second;
+ if (!(this->*func)(&state, value)) {
+ LOG(ERROR) << "Failed to parse \"" << key << "\" entry.";
+ return false;
+ }
+ }
+ }
return true;
}
-bool CellularOperatorInfo::GetOLP(const string &operator_id,
- CellularService::OLP *olp) {
- if (!info_file_.ContainsGroup(operator_id)) {
- LOG(INFO) << "Could not find cellular operator '" << operator_id << "'.";
+bool CellularOperatorInfo::HandleCountry(ParserState *state,
+ const string &value) {
+ state->country = value;
+ return true;
+}
+
+bool CellularOperatorInfo::HandleNameKey(ParserState *state,
+ const string &value) {
+ if (state->parsing_apn)
+ return HandleAPNName(state, value);
+ return HandleName(state, value);
+}
+
+bool CellularOperatorInfo::HandleProvider(ParserState *state,
+ const string &value) {
+ state->parsing_apn = false;
+
+ vector<string> fields;
+ base::SplitString(value, ',', &fields);
+ if (fields.size() != 4) {
+ LOG(ERROR) << "Badly formed \"provider\" entry.";
return false;
}
- string value;
- if (!info_file_.GetString(operator_id, kKeyOLPURL, &value)) {
- LOG(INFO) << "Could not find online payment portal info for cellular "
- << "operator '" << operator_id << "'.";
+ int is_primary = 0;
+ if (!base::StringToInt(fields[2], &is_primary)) {
+ LOG(ERROR) << "Badly formed value for \"is_primary\": " << fields[2];
+ return false;
+ }
+ int requires_roaming = 0;
+ if (!base::StringToInt(fields[3], &requires_roaming)) {
+ LOG(ERROR) << "Badly formed value for \"requires_roaming\": "
+ << fields[3];
+ return false;
+ }
+ state->provider = new CellularOperator();
+ state->provider->is_primary_ = is_primary != 0;
+ state->provider->requires_roaming_ = requires_roaming != 0;
+ state->provider->country_ = state->country;
+
+ operators_.push_back(state->provider);
+ return true;
+}
+
+bool CellularOperatorInfo::HandleMCCMNC(ParserState *state,
+ const string &value) {
+ if (value.empty()) {
+ LOG(ERROR) << "Empty \"mccmnc\" value.";
+ return false;
+ }
+ if (!state->provider) {
+ LOG(ERROR) << "Found \"mccmnc\" entry without \"provider\".";
return false;
}
- olp->SetURL(value);
-
- if (info_file_.GetString(operator_id, kKeyOLPMethod, &value)) {
- olp->SetMethod(value);
- } else {
- olp->SetMethod("");
+ vector<string> mccmnc_list;
+ base::SplitString(value, ',', &mccmnc_list);
+ if ((mccmnc_list.size() % 2) != 0) {
+ LOG(ERROR) << "Badly formatted \"mccmnc\" entry. "
+ << "Expected even number of elements.";
+ return false;
}
- if (info_file_.GetString(operator_id, kKeyOLPPostData, &value)) {
- olp->SetPostData(value);
- } else {
- olp->SetPostData("");
+ for (size_t i = 0; i < mccmnc_list.size(); i += 2) {
+ const string &mccmnc = mccmnc_list[i];
+ if (!mccmnc.empty()) {
+ state->provider->mccmnc_list_.push_back(mccmnc);
+ mccmnc_to_operator_[mccmnc] = state->provider;
+ int index = -1;
+ if (base::StringToInt(mccmnc_list[i + 1], &index))
+ state->provider->mccmnc_to_olp_idx_[mccmnc] = index;
+ }
+ }
+ return true;
+}
+
+bool CellularOperatorInfo::HandleAPN(ParserState *state,
+ const string &value) {
+ if (!state->provider) {
+ LOG(ERROR) << "Found \"apn\" entry without \"provider\".";
+ return false;
+ }
+ vector<string> fields;
+ base::SplitString(value, ',', &fields);
+ if (fields.size() != 4) {
+ LOG(ERROR) << "Badly formed \"apn\" entry.";
+ return false;
+ }
+ state->apn = new MobileAPN();
+ state->apn->apn_ = fields[1];
+ state->apn->username_ = fields[2];
+ state->apn->password_ = fields[3];
+ state->provider->apn_list_.push_back(state->apn);
+ state->parsing_apn = true;
+ return true;
+}
+
+bool CellularOperatorInfo::HandleAPNName(ParserState *state,
+ const string &value) {
+ if (!(state->parsing_apn && state->apn)) {
+ LOG(ERROR) << "APN not being parsed.";
+ return false;
+ }
+ LocalizedName name;
+ if (!ParseNameLine(value, &name))
+ return false;
+ state->apn->name_list_.push_back(name);
+ return true;
+}
+
+bool CellularOperatorInfo::HandleName(ParserState *state,
+ const string &value) {
+ if (!state->provider) {
+ LOG(ERROR) << "Found \"name\" entry without \"provider\".";
+ return false;
+ }
+ LocalizedName name;
+ if (!ParseNameLine(value, &name))
+ return false;
+ if (state->provider->name_list_.size() == 0) {
+ vector<const CellularOperator *> &matching_operators =
+ name_to_operators_[name.name];
+ matching_operators.push_back(state->provider);
+ }
+ state->provider->name_list_.push_back(name);
+ return true;
+}
+
+bool CellularOperatorInfo::ParseNameLine(const string &value,
+ LocalizedName *name) {
+ vector<string> fields;
+ base::SplitString(value, ',', &fields);
+ if (fields.size() != 2) {
+ LOG(ERROR) << "Badly formed \"name\" entry.";
+ return false;
+ }
+ name->language = fields[0];
+ name->name = fields[1];
+ return true;
+}
+
+bool CellularOperatorInfo::HandleSID(ParserState *state,
+ const string &value) {
+ if (value.empty()) {
+ LOG(ERROR) << "Empty \"sid\" value.";
+ return false;
+ }
+ if (!state->provider) {
+ LOG(ERROR) << "Found \"sid\" entry without \"provider\".";
+ return false;
+ }
+ vector<string> sid_list;
+ base::SplitString(value, ',', &sid_list);
+ if ((sid_list.size() % 2) != 0) {
+ LOG(ERROR) << "Badly formatted \"sid\" entry. "
+ << "Expected even number of elements. ";
+ return false;
}
+ for (size_t i = 0; i < sid_list.size(); i += 2) {
+ const string &sid = sid_list[i];
+ if (!sid.empty()) {
+ state->provider->sid_list_.push_back(sid);
+ sid_to_operator_[sid] = state->provider;
+ int index = -1;
+ if (base::StringToInt(sid_list[i + 1], &index))
+ state->provider->sid_to_olp_idx_[sid] = index;
+ }
+ }
+ return true;
+}
+
+bool CellularOperatorInfo::HandleOLP(ParserState *state,
+ const string &value) {
+ if (!state->provider) {
+ LOG(ERROR) << "Found \"olp\" entry without \"provider\"";
+ return false;
+ }
+ vector<string> fields;
+ base::SplitString(value, ',', &fields);
+ if (fields.size() != 3) {
+ LOG(ERROR) << "Badly formed \"apn\" entry.";
+ return false;
+ }
+ CellularService::OLP *olp = new CellularService::OLP();
+ olp->SetMethod(fields[0]);
+ olp->SetURL(fields[1]);
+ olp->SetPostData(fields[2]);
+
+ state->provider->olp_list_.push_back(olp);
return true;
}
diff --git a/cellular_operator_info.h b/cellular_operator_info.h
index f09f319..8e9c0fd 100644
--- a/cellular_operator_info.h
+++ b/cellular_operator_info.h
@@ -1,37 +1,193 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2013 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.
#ifndef SHILL_CELLULAR_OPERATOR_INFO_H_
#define SHILL_CELLULAR_OPERATOR_INFO_H_
+#include <map>
#include <string>
+#include <vector>
#include <base/basictypes.h>
#include <base/file_path.h>
+#include <base/memory/scoped_vector.h>
+#include <gtest/gtest_prod.h> // for FRIEND_TEST
#include "shill/cellular_service.h"
+#include "shill/file_reader.h"
#include "shill/key_file_store.h"
namespace shill {
-class GLib;
-
class CellularOperatorInfo {
public:
- explicit CellularOperatorInfo(GLib *glib);
+ CellularOperatorInfo();
virtual ~CellularOperatorInfo();
+ struct LocalizedName {
+ std::string name;
+ std::string language;
+ };
+
+ class MobileAPN {
+ public:
+ MobileAPN();
+ ~MobileAPN();
+
+ const std::string &apn() const { return apn_; }
+ const std::vector<LocalizedName> &name_list() const { return name_list_; }
+ const std::string &username() const { return username_; }
+ const std::string &password() const { return password_; }
+
+ private:
+ friend class CellularOperatorInfo;
+
+ std::string apn_;
+ std::vector<LocalizedName> name_list_;
+ std::string username_;
+ std::string password_;
+
+ DISALLOW_COPY_AND_ASSIGN(MobileAPN);
+ };
+
+ class CellularOperator {
+ public:
+ CellularOperator();
+ virtual ~CellularOperator();
+
+ const std::string &country() const { return country_; }
+ const std::vector<std::string> &mccmnc_list() const {
+ return mccmnc_list_;
+ }
+ const std::vector<std::string> &sid_list() const { return sid_list_; }
+ const std::vector<LocalizedName> &name_list() const { return name_list_; }
+ const ScopedVector<MobileAPN> &apn_list() const { return apn_list_; }
+ const ScopedVector<CellularService::OLP> &olp_list() const {
+ return olp_list_;
+ }
+ bool is_primary() const { return is_primary_; }
+ bool requires_roaming() const { return requires_roaming_; }
+
+ private:
+ friend class CellularOperatorInfo;
+ friend class CellularOperatorInfoTest;
+ FRIEND_TEST(CellularOperatorInfoTest, HandleMCCMNC);
+ FRIEND_TEST(CellularOperatorInfoTest, HandleSID);
+
+ std::string country_;
+ std::vector<std::string> mccmnc_list_;
+ std::vector<std::string> sid_list_;
+ std::vector<LocalizedName> name_list_;
+ ScopedVector<MobileAPN> apn_list_;
+ ScopedVector<CellularService::OLP> olp_list_;
+ std::map<std::string, uint32> mccmnc_to_olp_idx_;
+ std::map<std::string, uint32> sid_to_olp_idx_;
+ bool is_primary_;
+ bool requires_roaming_;
+
+ DISALLOW_COPY_AND_ASSIGN(CellularOperator);
+ };
+
// Loads the operator info from |info_file_path|. Returns true on success.
virtual bool Load(const FilePath &info_file_path);
- // Gets the online payment portal info of the operator with ID |operator_id|.
- // Returns true if the info is found.
- virtual bool GetOLP(const std::string &operator_id,
- CellularService::OLP *olp);
+ // Gets the cellular operator info of the operator with MCCMNC |mccmnc|.
+ // If found, returns a pointer to the matching operator.
+ virtual const CellularOperator *
+ GetCellularOperatorByMCCMNC(const std::string &mccmnc);
+
+ // Gets the cellular operator info of the operator with SID |sid|.
+ // If found, returns a pointer to the matching operator.
+ virtual const CellularOperator *
+ GetCellularOperatorBySID(const std::string &sid);
+
+ // Gets the cellular operator info of the operators that match the name
+ // |name|, such that each element contains information about the operator
+ // in different countries. The given name must be the first enumerated name
+ // for the operator in the operator database.
+ // If found, returns a pointer to a vector containing the matching operators.
+ virtual const std::vector<const CellularOperator *> *
+ GetCellularOperatorsByName(const std::string &name);
+
+ // Gets the online payment portal info of the operator with MCCMNC |mccmnc|.
+ // If found, returns a pointer to the matching OLP.
+ virtual const CellularService::OLP *GetOLPByMCCMNC(const std::string &mccmnc);
+
+ // Gets the online payment portal info of the operator with SID |sid|.
+ // If found, returns a pointer to the matching OLP.
+ virtual const CellularService::OLP *GetOLPBySID(const std::string &sid);
+
+ // Returns a list of all operators.
+ virtual const ScopedVector<CellularOperator> &operators() const;
private:
- KeyFileStore info_file_;
+ friend class CellularOperatorInfoTest;
+ FRIEND_TEST(CellularOperatorInfoTest, HandleAPN);
+ FRIEND_TEST(CellularOperatorInfoTest, HandleAPNName);
+ FRIEND_TEST(CellularOperatorInfoTest, HandleMCCMNC);
+ FRIEND_TEST(CellularOperatorInfoTest, HandleName);
+ FRIEND_TEST(CellularOperatorInfoTest, HandleOLP);
+ FRIEND_TEST(CellularOperatorInfoTest, HandleProvider);
+ FRIEND_TEST(CellularOperatorInfoTest, HandleSID);
+ FRIEND_TEST(CellularOperatorInfoTest, ParseKeyValue);
+ FRIEND_TEST(CellularOperatorInfoTest, ParseNameLine);
+ FRIEND_TEST(CellularOperatorInfoTest, ParseSuccess);
+
+ struct ParserState {
+ ParserState() : provider(NULL),
+ apn(NULL),
+ parsing_apn(false) {}
+
+ std::string country;
+ CellularOperator *provider;
+ MobileAPN *apn;
+
+ bool parsing_apn;
+ };
+
+ bool HandleProvider(ParserState *state,
+ const std::string &value);
+ bool HandleMCCMNC(ParserState *state,
+ const std::string &value);
+ bool HandleNameKey(ParserState *state,
+ const std::string &value);
+ bool HandleName(ParserState *state,
+ const std::string &value);
+ bool HandleAPN(ParserState *state,
+ const std::string &value);
+ bool HandleAPNName(ParserState *state,
+ const std::string &value);
+ bool HandleSID(ParserState *state,
+ const std::string &value);
+ bool HandleOLP(ParserState *state,
+ const std::string &value);
+ bool HandleCountry(ParserState *state,
+ const std::string &value);
+ bool ParseNameLine(const std::string &value,
+ LocalizedName *name);
+
+ void ClearOperators();
+
+ // Functions that return specially formatted strings for logging
+ // MCCMNC and SID to help with scrubbing.
+ static std::string FormattedMCCMNC(const std::string &mccmnc);
+ static std::string FormattedSID(const std::string &sid);
+
+ // Splits |line| into two strings, separated with the |key_value_delimiter|.
+ // Returns |false| if line does not contain |key_value_delimiter|, otherwise
+ // returns the first substring in |key| and the second substring in |value|,
+ // and returns true.
+ static bool ParseKeyValue(const std::string &line,
+ char key_value_delimiter,
+ std::string *key,
+ std::string *value);
+
+ ScopedVector<CellularOperator> operators_;
+ std::map<std::string, CellularOperator *> mccmnc_to_operator_;
+ std::map<std::string, CellularOperator *> sid_to_operator_;
+ std::map<std::string,
+ std::vector<const CellularOperator *> > name_to_operators_;
DISALLOW_COPY_AND_ASSIGN(CellularOperatorInfo);
};
diff --git a/cellular_operator_info_unittest.cc b/cellular_operator_info_unittest.cc
index 5537e97..87ec7b8 100644
--- a/cellular_operator_info_unittest.cc
+++ b/cellular_operator_info_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2013 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.
@@ -7,7 +7,9 @@
#include <base/file_util.h>
#include <gtest/gtest.h>
+using std::map;
using std::string;
+using std::vector;
namespace shill {
@@ -17,22 +19,37 @@
"#\n"
"# Comments\n"
"#\n"
- "[000001]\n"
- "OLP.URL=https://testurl\n"
- "OLP.Method=POST\n"
- "OLP.PostData=imei=${imei}&iccid=${iccid}\n"
+ "serviceproviders:3.0\n"
+ "country:us\n"
"\n"
- "[000002]\n"
- "OLP.URL=https://testurl2\n"
+ "# TestProvider1\n"
+ "provider:1,1,0,1\n"
+ "name:,TestProvider1\n"
+ "mccmnc:000001,0,000002,0\n"
+ "sid:1,0,2,0,3,0\n"
+ "olp:POST,https://testurl,imei=${imei}&iccid=${iccid}\n"
+ "apn:2,testprovider1apn,,\n"
+ "name:en,Test Provider 1\n"
+ "name:de,Testmobilfunkanbieter 1\n"
"\n"
- "[000003]\n"
- "Name=test\n";
+ "# TestProvider2\n"
+ "provider:1,2,1,0\n"
+ "name:,TestProviderTwo\n"
+ "name:,TestProvider2\n"
+ "mccmnc:100001,1,100002,0\n"
+ "sid:4,0,5,1\n"
+ "olp:,https://testurl2,\n"
+ "olp:,https://testurl3,\n"
+ "apn:1,testprovider2apn,,\n"
+ "name:,Test Provider 2\n"
+ "apn:1,testprovider2apn2,testusername,testpassword\n"
+ "name:tr,Test Operatoru 2\n";
} // namespace
class CellularOperatorInfoTest : public testing::Test {
public:
- CellularOperatorInfoTest() : info_(&glib_) {}
+ CellularOperatorInfoTest() {}
protected:
void SetUp() {
@@ -51,22 +68,419 @@
CellularOperatorInfo info_;
};
-TEST_F(CellularOperatorInfoTest, GetOLP) {
+TEST_F(CellularOperatorInfoTest, ParseSuccess) {
+ EXPECT_TRUE(info_.Load(info_file_path_));
+ EXPECT_EQ(info_.operators().size(), 2);
+
+ const CellularOperatorInfo::CellularOperator *provider = info_.operators()[0];
+ EXPECT_FALSE(provider->is_primary());
+ EXPECT_TRUE(provider->requires_roaming());
+ EXPECT_EQ(provider->country(), "us");
+ EXPECT_EQ(provider->name_list().size(), 1);
+ EXPECT_EQ(provider->name_list()[0].language, "");
+ EXPECT_EQ(provider->name_list()[0].name, "TestProvider1");
+ EXPECT_EQ(provider->mccmnc_list().size(), 2);
+ EXPECT_EQ(provider->mccmnc_list()[0], "000001");
+ EXPECT_EQ(provider->mccmnc_list()[1], "000002");
+ EXPECT_EQ(provider->sid_list().size(), 3);
+ EXPECT_EQ(provider->sid_list()[0], "1");
+ EXPECT_EQ(provider->sid_list()[1], "2");
+ EXPECT_EQ(provider->sid_list()[2], "3");
+ EXPECT_EQ(provider->olp_list().size(), 1);
+ EXPECT_EQ(provider->olp_list()[0]->GetURL(), "https://testurl");
+ EXPECT_EQ(provider->olp_list()[0]->GetMethod(), "POST");
+ EXPECT_EQ(provider->olp_list()[0]->GetPostData(),
+ "imei=${imei}&iccid=${iccid}");
+ EXPECT_EQ(provider->apn_list().size(), 1);
+ EXPECT_EQ(provider->apn_list()[0]->apn(), "testprovider1apn");
+ EXPECT_EQ(provider->apn_list()[0]->username(), "");
+ EXPECT_EQ(provider->apn_list()[0]->password(), "");
+ EXPECT_EQ(provider->apn_list()[0]->name_list().size(), 2);
+ EXPECT_EQ(provider->apn_list()[0]->name_list()[0].language, "en");
+ EXPECT_EQ(provider->apn_list()[0]->name_list()[0].name, "Test Provider 1");
+ EXPECT_EQ(provider->apn_list()[0]->name_list()[1].language, "de");
+ EXPECT_EQ(provider->apn_list()[0]->name_list()[1].name,
+ "Testmobilfunkanbieter 1");
+
+ const CellularOperatorInfo::CellularOperator *provider2 =
+ info_.operators()[1];
+ EXPECT_TRUE(provider2->is_primary());
+ EXPECT_FALSE(provider2->requires_roaming());
+ EXPECT_EQ(provider2->country(), "us");
+ EXPECT_EQ(provider2->name_list().size(), 2);
+ EXPECT_EQ(provider2->name_list()[0].language, "");
+ EXPECT_EQ(provider2->name_list()[0].name, "TestProviderTwo");
+ EXPECT_EQ(provider2->name_list()[1].language, "");
+ EXPECT_EQ(provider2->name_list()[1].name, "TestProvider2");
+ EXPECT_EQ(provider2->mccmnc_list().size(), 2);
+ EXPECT_EQ(provider2->mccmnc_list()[0], "100001");
+ EXPECT_EQ(provider2->mccmnc_list()[1], "100002");
+ EXPECT_EQ(provider2->sid_list().size(), 2);
+ EXPECT_EQ(provider2->sid_list()[0], "4");
+ EXPECT_EQ(provider2->sid_list()[1], "5");
+ EXPECT_EQ(provider2->olp_list().size(), 2);
+ EXPECT_EQ(provider2->olp_list()[0]->GetURL(), "https://testurl2");
+ EXPECT_EQ(provider2->olp_list()[0]->GetMethod(), "");
+ EXPECT_EQ(provider2->olp_list()[0]->GetPostData(), "");
+ EXPECT_EQ(provider2->olp_list()[1]->GetURL(), "https://testurl3");
+ EXPECT_EQ(provider2->olp_list()[1]->GetMethod(), "");
+ EXPECT_EQ(provider2->olp_list()[1]->GetPostData(), "");
+ EXPECT_EQ(provider2->apn_list().size(), 2);
+ EXPECT_EQ(provider2->apn_list()[0]->apn(), "testprovider2apn");
+ EXPECT_EQ(provider2->apn_list()[0]->username(), "");
+ EXPECT_EQ(provider2->apn_list()[0]->password(), "");
+ EXPECT_EQ(provider2->apn_list()[0]->name_list().size(), 1);
+ EXPECT_EQ(provider2->apn_list()[0]->name_list()[0].language, "");
+ EXPECT_EQ(provider2->apn_list()[0]->name_list()[0].name, "Test Provider 2");
+ EXPECT_EQ(provider2->apn_list()[1]->apn(), "testprovider2apn2");
+ EXPECT_EQ(provider2->apn_list()[1]->username(), "testusername");
+ EXPECT_EQ(provider2->apn_list()[1]->password(), "testpassword");
+ EXPECT_EQ(provider2->apn_list()[1]->name_list().size(), 1);
+ EXPECT_EQ(provider2->apn_list()[1]->name_list()[0].language, "tr");
+ EXPECT_EQ(provider2->apn_list()[1]->name_list()[0].name, "Test Operatoru 2");
+}
+
+TEST_F(CellularOperatorInfoTest, GetCellularOperatorByMCCMNC) {
EXPECT_TRUE(info_.Load(info_file_path_));
- CellularService::OLP olp;
- EXPECT_TRUE(info_.GetOLP("000001", &olp));
- EXPECT_EQ("https://testurl", olp.GetURL());
- EXPECT_EQ("POST", olp.GetMethod());
- EXPECT_EQ("imei=${imei}&iccid=${iccid}", olp.GetPostData());
+ EXPECT_FALSE(info_.GetCellularOperatorByMCCMNC("1"));
+ EXPECT_FALSE(info_.GetCellularOperatorByMCCMNC("000003"));
+ EXPECT_FALSE(info_.GetCellularOperatorByMCCMNC("bananas"));
+ EXPECT_FALSE(info_.GetCellularOperatorByMCCMNC("abcd"));
- EXPECT_TRUE(info_.GetOLP("000002", &olp));
- EXPECT_EQ("https://testurl2", olp.GetURL());
- EXPECT_EQ("", olp.GetMethod());
- EXPECT_EQ("", olp.GetPostData());
+ const CellularOperatorInfo::CellularOperator *provider = NULL;
+ EXPECT_TRUE((provider = info_.GetCellularOperatorByMCCMNC("000001")));
+ EXPECT_EQ(provider, info_.operators()[0]);
+ EXPECT_TRUE((provider = info_.GetCellularOperatorByMCCMNC("100001")));
+ EXPECT_EQ(provider, info_.operators()[1]);
+ EXPECT_TRUE((provider = info_.GetCellularOperatorByMCCMNC("000002")));
+ EXPECT_EQ(provider, info_.operators()[0]);
+ EXPECT_TRUE((provider = info_.GetCellularOperatorByMCCMNC("100002")));
+ EXPECT_EQ(provider, info_.operators()[1]);
+}
- EXPECT_FALSE(info_.GetOLP("000003", &olp));
- EXPECT_FALSE(info_.GetOLP("000004", &olp));
+TEST_F(CellularOperatorInfoTest, GetCellularOperatorBySID) {
+ EXPECT_TRUE(info_.Load(info_file_path_));
+
+ EXPECT_FALSE(info_.GetCellularOperatorBySID("000001"));
+ EXPECT_FALSE(info_.GetCellularOperatorBySID("000002"));
+ EXPECT_FALSE(info_.GetCellularOperatorBySID("100001"));
+ EXPECT_FALSE(info_.GetCellularOperatorBySID("100002"));
+ EXPECT_FALSE(info_.GetCellularOperatorBySID("banana"));
+
+ const CellularOperatorInfo::CellularOperator *provider = NULL;
+ EXPECT_TRUE((provider = info_.GetCellularOperatorBySID("1")));
+ EXPECT_EQ(provider, info_.operators()[0]);
+ EXPECT_TRUE((provider = info_.GetCellularOperatorBySID("4")));
+ EXPECT_EQ(provider, info_.operators()[1]);
+ EXPECT_TRUE((provider = info_.GetCellularOperatorBySID("2")));
+ EXPECT_EQ(provider, info_.operators()[0]);
+ EXPECT_TRUE((provider = info_.GetCellularOperatorBySID("5")));
+ EXPECT_EQ(provider, info_.operators()[1]);
+ EXPECT_TRUE((provider = info_.GetCellularOperatorBySID("3")));
+ EXPECT_EQ(provider, info_.operators()[0]);
+}
+
+TEST_F(CellularOperatorInfoTest, GetCellularOperatorsByName) {
+ EXPECT_TRUE(info_.Load(info_file_path_));
+
+ const vector<const CellularOperatorInfo::CellularOperator *> *list = NULL;
+ EXPECT_FALSE(info_.GetCellularOperatorsByName("banana"));
+ EXPECT_FALSE(info_.GetCellularOperatorsByName("TestProvider2"));
+
+ EXPECT_TRUE((list = info_.GetCellularOperatorsByName("TestProvider1")));
+ EXPECT_EQ(list->size(), 1);
+ EXPECT_EQ((*list)[0]->apn_list()[0]->apn(), "testprovider1apn");
+
+ EXPECT_FALSE(info_.GetCellularOperatorsByName("TestProvider2"));
+
+ EXPECT_TRUE((list = info_.GetCellularOperatorsByName("TestProviderTwo")));
+ EXPECT_EQ(list->size(), 1);
+ EXPECT_EQ((*list)[0]->apn_list()[0]->apn(), "testprovider2apn");
+}
+
+TEST_F(CellularOperatorInfoTest, GetOLPByMCCMNC) {
+ EXPECT_TRUE(info_.Load(info_file_path_));
+
+ const CellularService::OLP *olp = NULL;
+ EXPECT_TRUE((olp = info_.GetOLPByMCCMNC("000001")));
+ EXPECT_EQ("https://testurl", olp->GetURL());
+ EXPECT_EQ("POST", olp->GetMethod());
+ EXPECT_EQ("imei=${imei}&iccid=${iccid}", olp->GetPostData());
+
+ EXPECT_TRUE((olp = info_.GetOLPByMCCMNC("000002")));
+ EXPECT_EQ("https://testurl", olp->GetURL());
+ EXPECT_EQ("POST", olp->GetMethod());
+ EXPECT_EQ("imei=${imei}&iccid=${iccid}", olp->GetPostData());
+
+ EXPECT_TRUE((olp = info_.GetOLPByMCCMNC("100001")));
+ EXPECT_EQ("https://testurl3", olp->GetURL());
+ EXPECT_EQ("", olp->GetMethod());
+ EXPECT_EQ("", olp->GetPostData());
+
+ EXPECT_TRUE((olp = info_.GetOLPByMCCMNC("100002")));
+ EXPECT_EQ("https://testurl2", olp->GetURL());
+ EXPECT_EQ("", olp->GetMethod());
+ EXPECT_EQ("", olp->GetPostData());
+
+ EXPECT_FALSE(info_.GetOLPByMCCMNC("000003"));
+ EXPECT_FALSE(info_.GetOLPByMCCMNC("000004"));
+}
+
+TEST_F(CellularOperatorInfoTest, GetOLPBySID) {
+ EXPECT_TRUE(info_.Load(info_file_path_));
+
+ const CellularService::OLP *olp = NULL;
+ EXPECT_TRUE((olp = info_.GetOLPBySID("1")));
+ EXPECT_EQ("https://testurl", olp->GetURL());
+ EXPECT_EQ("POST", olp->GetMethod());
+ EXPECT_EQ("imei=${imei}&iccid=${iccid}", olp->GetPostData());
+
+ EXPECT_TRUE((olp = info_.GetOLPBySID("2")));
+ EXPECT_EQ("https://testurl", olp->GetURL());
+ EXPECT_EQ("POST", olp->GetMethod());
+ EXPECT_EQ("imei=${imei}&iccid=${iccid}", olp->GetPostData());
+
+ EXPECT_TRUE((olp = info_.GetOLPBySID("3")));
+ EXPECT_EQ("https://testurl", olp->GetURL());
+ EXPECT_EQ("POST", olp->GetMethod());
+ EXPECT_EQ("imei=${imei}&iccid=${iccid}", olp->GetPostData());
+
+ EXPECT_TRUE((olp = info_.GetOLPBySID("4")));
+ EXPECT_EQ("https://testurl2", olp->GetURL());
+ EXPECT_EQ("", olp->GetMethod());
+ EXPECT_EQ("", olp->GetPostData());
+
+ EXPECT_TRUE((olp = info_.GetOLPBySID("5")));
+ EXPECT_EQ("https://testurl3", olp->GetURL());
+ EXPECT_EQ("", olp->GetMethod());
+ EXPECT_EQ("", olp->GetPostData());
+
+ EXPECT_FALSE(info_.GetOLPBySID("6"));
+ EXPECT_FALSE(info_.GetOLPBySID("7"));
+}
+
+TEST_F(CellularOperatorInfoTest, HandleProvider) {
+ CellularOperatorInfo::ParserState state;
+ EXPECT_FALSE(info_.HandleProvider(&state, "0,0,0"));
+ EXPECT_FALSE(state.provider);
+ EXPECT_EQ(info_.operators_.size(), 0);
+
+ EXPECT_TRUE(info_.HandleProvider(&state, "0,0,0,0"));
+ EXPECT_TRUE(state.provider);
+ EXPECT_EQ(info_.operators_.size(), 1);
+ EXPECT_FALSE(state.provider->is_primary());
+ EXPECT_FALSE(state.provider->requires_roaming());
+
+ EXPECT_TRUE(info_.HandleProvider(&state, "1,1,0,1"));
+ EXPECT_EQ(info_.operators_.size(), 2);
+ EXPECT_EQ(state.provider, info_.operators_[1]);
+ EXPECT_FALSE(state.provider->is_primary());
+ EXPECT_TRUE(state.provider->requires_roaming());
+}
+
+TEST_F(CellularOperatorInfoTest, HandleMCCMNC) {
+ CellularOperatorInfo::ParserState state;
+ EXPECT_FALSE(info_.HandleMCCMNC(&state, "1,1"));
+
+ EXPECT_TRUE(info_.HandleProvider(&state, "1,1,0,0"));
+ EXPECT_TRUE(state.provider);
+
+ EXPECT_FALSE(info_.HandleMCCMNC(&state, ""));
+ EXPECT_TRUE(state.provider->mccmnc_list().empty());
+ EXPECT_TRUE(info_.mccmnc_to_operator_.empty());
+
+ EXPECT_FALSE(info_.HandleMCCMNC(&state, "000001,0,000002"));
+ EXPECT_TRUE(state.provider->mccmnc_list().empty());
+ EXPECT_TRUE(info_.mccmnc_to_operator_.empty());
+
+ EXPECT_TRUE(info_.HandleMCCMNC(&state, "000001,0,000002,3"));
+ EXPECT_EQ(state.provider->mccmnc_list().size(), 2);
+ EXPECT_EQ(info_.mccmnc_to_operator_.size(), 2);
+ EXPECT_EQ(info_.mccmnc_to_operator_["000001"], state.provider);
+ EXPECT_EQ(info_.mccmnc_to_operator_["000002"], state.provider);
+ EXPECT_EQ(state.provider->mccmnc_list()[0], "000001");
+ EXPECT_EQ(state.provider->mccmnc_list()[1], "000002");
+ EXPECT_EQ(state.provider->mccmnc_to_olp_idx_.size(), 2);
+ EXPECT_EQ(state.provider->mccmnc_to_olp_idx_["000001"], 0);
+ EXPECT_EQ(state.provider->mccmnc_to_olp_idx_["000002"], 3);
+}
+
+TEST_F(CellularOperatorInfoTest, HandleName) {
+ CellularOperatorInfo::ParserState state;
+ EXPECT_FALSE(info_.HandleName(&state, ","));
+
+ EXPECT_TRUE(info_.HandleProvider(&state, "1,1,0,0"));
+ EXPECT_TRUE(state.provider);
+ EXPECT_TRUE(state.provider->name_list().empty());
+
+ EXPECT_FALSE(info_.HandleName(&state, ",,"));
+ EXPECT_TRUE(state.provider->name_list().empty());
+
+ EXPECT_TRUE(info_.HandleName(&state, "en,Test Name"));
+ EXPECT_EQ(state.provider->name_list().size(), 1);
+
+ const CellularOperatorInfo::LocalizedName &name =
+ state.provider->name_list()[0];
+ EXPECT_EQ(name.language, "en");
+ EXPECT_EQ(name.name, "Test Name");
+
+ EXPECT_TRUE(info_.HandleName(&state, ",Other Test Name"));
+ EXPECT_EQ(state.provider->name_list().size(), 2);
+
+ const CellularOperatorInfo::LocalizedName &name2 =
+ state.provider->name_list()[1];
+ EXPECT_EQ(name2.language, "");
+ EXPECT_EQ(name2.name, "Other Test Name");
+}
+
+TEST_F(CellularOperatorInfoTest, HandleAPN) {
+ CellularOperatorInfo::ParserState state;
+ EXPECT_FALSE(info_.HandleAPN(&state, ",,,"));
+
+ EXPECT_TRUE(info_.HandleProvider(&state, "1,1,0,0"));
+ EXPECT_TRUE(state.provider);
+ EXPECT_TRUE(state.provider->apn_list().empty());
+
+ EXPECT_FALSE(info_.HandleAPN(&state, ","));
+ EXPECT_TRUE(state.provider->apn_list().empty());
+
+ EXPECT_FALSE(state.parsing_apn);
+
+ EXPECT_TRUE(info_.HandleAPN(&state, "0,testapn,testusername,testpassword"));
+ EXPECT_EQ(state.provider->apn_list().size(), 1);
+ EXPECT_TRUE(state.parsing_apn);
+
+ const CellularOperatorInfo::MobileAPN *apn = state.provider->apn_list()[0];
+ EXPECT_EQ(apn->apn(), "testapn");
+ EXPECT_EQ(apn->username(), "testusername");
+ EXPECT_EQ(apn->password(), "testpassword");
+}
+
+TEST_F(CellularOperatorInfoTest, HandleAPNName) {
+ CellularOperatorInfo::ParserState state;
+ EXPECT_FALSE(info_.HandleAPNName(&state, ","));
+ state.parsing_apn = true;
+ EXPECT_FALSE(info_.HandleAPNName(&state, ","));
+ state.parsing_apn = false;
+ state.apn = (CellularOperatorInfo::MobileAPN *)1;
+ EXPECT_FALSE(info_.HandleAPNName(&state, ","));
+
+ EXPECT_TRUE(info_.HandleProvider(&state, "1,1,0,0"));
+ EXPECT_TRUE(state.provider);
+ EXPECT_TRUE(info_.HandleAPN(&state, ",,,"));
+ EXPECT_TRUE(state.parsing_apn && state.apn);
+
+ const CellularOperatorInfo::MobileAPN *apn = state.provider->apn_list()[0];
+
+ EXPECT_FALSE(info_.HandleAPNName(&state, ",,"));
+ EXPECT_EQ(apn->name_list().size(), 0);
+
+ EXPECT_TRUE(info_.HandleAPNName(&state, "en,APN Name"));
+ EXPECT_EQ(apn->name_list().size(), 1);
+
+ const CellularOperatorInfo::LocalizedName &name = apn->name_list()[0];
+ EXPECT_EQ(name.language, "en");
+ EXPECT_EQ(name.name, "APN Name");
+
+ EXPECT_TRUE(info_.HandleAPNName(&state, ",Other APN Name"));
+ EXPECT_EQ(apn->name_list().size(), 2);
+
+ const CellularOperatorInfo::LocalizedName &name2 = apn->name_list()[1];
+ EXPECT_EQ(name2.language, "");
+ EXPECT_EQ(name2.name, "Other APN Name");
+}
+
+TEST_F(CellularOperatorInfoTest, HandleSID) {
+ CellularOperatorInfo::ParserState state;
+ EXPECT_FALSE(info_.HandleSID(&state, "1,0"));
+
+ EXPECT_TRUE(info_.HandleProvider(&state, "1,1,0,0"));
+ EXPECT_TRUE(state.provider);
+
+ EXPECT_FALSE(info_.HandleSID(&state, ""));
+ EXPECT_TRUE(state.provider->sid_list().empty());
+ EXPECT_TRUE(info_.sid_to_operator_.empty());
+
+ EXPECT_FALSE(info_.HandleSID(&state, "1,2,3"));
+ EXPECT_TRUE(state.provider->sid_list().empty());
+ EXPECT_TRUE(info_.sid_to_operator_.empty());
+
+ EXPECT_TRUE(info_.HandleSID(&state, "1,5,2,3,3,0"));
+ EXPECT_EQ(state.provider->sid_list().size(), 3);
+ EXPECT_EQ(info_.sid_to_operator_.size(), 3);
+ EXPECT_EQ(info_.sid_to_operator_["1"], state.provider);
+ EXPECT_EQ(info_.sid_to_operator_["2"], state.provider);
+ EXPECT_EQ(info_.sid_to_operator_["3"], state.provider);
+ EXPECT_EQ(state.provider->sid_list()[0], "1");
+ EXPECT_EQ(state.provider->sid_list()[1], "2");
+ EXPECT_EQ(state.provider->sid_list()[2], "3");
+ EXPECT_EQ(state.provider->sid_to_olp_idx_.size(), 3);
+ EXPECT_EQ(state.provider->sid_to_olp_idx_["1"], 5);
+ EXPECT_EQ(state.provider->sid_to_olp_idx_["2"], 3);
+ EXPECT_EQ(state.provider->sid_to_olp_idx_["3"], 0);
+}
+
+TEST_F(CellularOperatorInfoTest, HandleOLP) {
+ CellularOperatorInfo::ParserState state;
+ EXPECT_FALSE(info_.HandleOLP(&state, ",,"));
+
+ EXPECT_TRUE(info_.HandleProvider(&state, "1,1,0,0"));
+ EXPECT_TRUE(state.provider);
+ EXPECT_EQ(0, state.provider->olp_list().size());
+
+ EXPECT_FALSE(info_.HandleOLP(&state, ","));
+ EXPECT_EQ(0, state.provider->olp_list().size());
+
+ EXPECT_TRUE(info_.HandleOLP(&state, ",,"));
+ EXPECT_EQ(1, state.provider->olp_list().size());
+ EXPECT_EQ(state.provider->olp_list()[0]->GetURL(), "");
+ EXPECT_EQ(state.provider->olp_list()[0]->GetMethod(), "");
+ EXPECT_EQ(state.provider->olp_list()[0]->GetPostData(), "");
+
+ EXPECT_TRUE(info_.HandleOLP(&state, "a,b,c"));
+ EXPECT_EQ(2, state.provider->olp_list().size());
+ EXPECT_EQ(state.provider->olp_list()[0]->GetURL(), "");
+ EXPECT_EQ(state.provider->olp_list()[0]->GetMethod(), "");
+ EXPECT_EQ(state.provider->olp_list()[0]->GetPostData(), "");
+ EXPECT_EQ(state.provider->olp_list()[1]->GetMethod(), "a");
+ EXPECT_EQ(state.provider->olp_list()[1]->GetURL(), "b");
+ EXPECT_EQ(state.provider->olp_list()[1]->GetPostData(), "c");
+}
+
+TEST_F(CellularOperatorInfoTest, ParseNameLine) {
+ CellularOperatorInfo::LocalizedName name;
+ EXPECT_FALSE(info_.ParseNameLine(",,", &name));
+ EXPECT_FALSE(info_.ParseNameLine("", &name));
+ EXPECT_TRUE(info_.ParseNameLine("a,b", &name));
+ EXPECT_EQ(name.language, "a");
+ EXPECT_EQ(name.name, "b");
+}
+
+TEST_F(CellularOperatorInfoTest, ParseKeyValue) {
+ string line = "key:value";
+ string key, value;
+ EXPECT_TRUE(CellularOperatorInfo::ParseKeyValue(line, ':', &key, &value));
+ EXPECT_EQ("key", key);
+ EXPECT_EQ("value", value);
+
+ line = "key:::::";
+ EXPECT_TRUE(CellularOperatorInfo::ParseKeyValue(line, ':', &key, &value));
+ EXPECT_EQ("key", key);
+ EXPECT_EQ("::::", value);
+
+ line = ":";
+ EXPECT_TRUE(CellularOperatorInfo::ParseKeyValue(line, ':', &key, &value));
+ EXPECT_EQ("", key);
+ EXPECT_EQ("", value);
+
+ line = ":value";
+ EXPECT_TRUE(CellularOperatorInfo::ParseKeyValue(line, ':', &key, &value));
+ EXPECT_EQ("", key);
+ EXPECT_EQ("value", value);
+
+ line = "";
+ EXPECT_FALSE(CellularOperatorInfo::ParseKeyValue(line, ':', &key, &value));
}
} // namespace shill
diff --git a/cellular_unittest.cc b/cellular_unittest.cc
index 38c2d95..2965480 100644
--- a/cellular_unittest.cc
+++ b/cellular_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2013 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.
@@ -709,8 +709,9 @@
// Service activation is needed
GetCapabilityUniversal()->mdn_ = "0000000000";
device_->cellular_operator_info_ = &cellular_operator_info_;
- EXPECT_CALL(cellular_operator_info_, GetOLP(_, _))
- .WillRepeatedly(Return(true));
+ CellularService::OLP olp;
+ EXPECT_CALL(cellular_operator_info_, GetOLPByMCCMNC(_))
+ .WillRepeatedly(Return(&olp));
device_->state_ = Cellular::kStateDisabled;
device_->HandleNewRegistrationState();
diff --git a/data/cellular_operator_info b/data/cellular_operator_info
index 614d94f..3e5df7d 100644
--- a/data/cellular_operator_info
+++ b/data/cellular_operator_info
@@ -1,12 +1,38 @@
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Copyright (c) 2013 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.
#
# This file contains information about cellular operators.
#
+# country:xx
+# <provider block 1>
+# <provider block 2>
+#
+# provider:<# of names>,<# of apns>,<primary>,<roaming>
+# name:<lang>,<name 1>
+# name:<lang>,<name 2>
+# ...
+# mccmnc:NNNNNN,<olp index>,NNNNNN,<olp index>...
+# sid:<sid>,<olp index>,<sid>,<olp index>...
+# olp:<method>,<url>,<postdata>
+# apn:<# of descriptive names>,<value>,<username>,<password>
+# name:<lang>,<descriptive name 1>
+# name:<lang>,<descriptive name 2>
+# ...
+# apn:<# of descriptive names>,<value>,<username>,<password>
+# ...
+#
+
+serviceproviders:3.0
+country:us
# Verizon Wireless
-[311480]
-OLP.URL=https://quickaccess.verizonwireless.com/bbportal/chrome/start4g.do
-OLP.Method=POST
-OLP.PostData=oem=GOG3&iccid=${iccid}&imei=${imei}&mdn=${mdn}
+provider:1,1,0,0
+name:,Verizon Wireless
+mccmnc:310995,0,311480,0
+sid:2,1,4,1,5,1,6,1,8,1,12,1,15,1,17,1,18,1,20,1,21,1,22,1,26,1,28,1,30,1,32,1,33,1,37,1,40,1,41,1,48,1,51,1,54,1,56,1,58,1,59,1,60,1,64,1,65,1,69,1,73,1,75,1,78,1,80,1,86,1,92,1,93,1,94,1,95,1,96,1,104,1,107,1,110,1,112,1,113,1,119,1,126,1,127,1,133,1,137,1,139,1,143,1,150,1,154,1,162,1,163,1,165,1,170,1,172,1,179,1,180,1,181,1,186,1,189,1,190,1,203,1,213,1,214,1,222,1,224,1,226,1,228,1,241,1,250,1,258,1,262,1,263,1,266,1,272,1,276,1,284,1,286,1,294,1,298,1,299,1,300,1,314,1,316,1,319,1,323,1,328,1,329,1,330,1,349,1,356,1,377,1,385,1,404,1,428,1,443,1,456,1,465,1,482,1,483,1,486,1,490,1,498,1,502,1,506,1,528,1,530,1,532,1,539,1,1015,1,1026,1,1032,1,1034,1,1062,1,1072,1,1074,1,1076,1,1083,1,1086,1,1088,1,1094,1,1103,1,1129,1,1131,1,1137,1,1139,1,1145,1,1151,1,1153,1,1164,1,1166,1,1174,1,1180,1,1189,1,1193,1,1196,1,1220,1,1224,1,1227,1,1230,1,1267,1,1285,1,1330,1,1358,1,1417,1,1429,1,1476,1,1488,1,1492,1,1494,1,1506,1,1510,1,1514,1,1516,1,1517,1,1519,1,1523,1,1548,1,1552,1,1563,1,1567,1,1614,1,1626,1,1630,1,1632,1,1637,1,1639,1,1641,1,1653,1,1679,1,1736,1,1740,1,1749,1,1760,1,1776,1,1780,1,1790,1,1792,1,1824,1,1826,1,1827,1,1830,1,1832,1,1857,1,1910,1,1912,1,1940,1,1969,1,2004,1,2054,1,2058,1,2060,1,2076,1,2115,1,2119,1,2125,1,2127,1,2149,1,3004,1,3008,1,3046,1,3066,1,3216,1,3218,1,3228,1,6709,1,6711,1,7532,1,7536,1,9640,1,9642,1,9644,1
+olp:POST,https://quickaccess.verizonwireless.com/bbportal/chrome/start4g.do,oem=GOG3&iccid=${iccid}&imei=${imei}&mdn=${mdn}
+# TODO(armansito): There may be different olp's for different US sid's.
+olp:POST,https://quickaccess.verizonwireless.com/bbportal/chrome/start.do,mdn=${mdn}&oem=GOG2&meid=${meid}
+apn:1,vzwinternet,,
+name:,4G LTE Contract
diff --git a/file_reader.cc b/file_reader.cc
index 81e52a4..450d7e0 100644
--- a/file_reader.cc
+++ b/file_reader.cc
@@ -26,7 +26,7 @@
bool FileReader::ReadLine(string *line) {
CHECK(line) << "Invalid argument";
- FILE* fp = file_.get();
+ FILE *fp = file_.get();
if (fp == NULL)
return false;
diff --git a/file_reader_unittest.cc b/file_reader_unittest.cc
new file mode 100644
index 0000000..85d51ed
--- /dev/null
+++ b/file_reader_unittest.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2013 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/file_reader.h"
+
+#include <string>
+#include <vector>
+
+#include <base/file_util.h>
+#include <base/scoped_temp_dir.h>
+#include <base/string_util.h>
+#include <gtest/gtest.h>
+
+using std::string;
+using std::vector;
+
+namespace shill {
+
+class FileReaderTest : public ::testing::Test {
+ public:
+ void VerifyReadLines(const FilePath& path, const vector<string>& lines) {
+ string line;
+ EXPECT_FALSE(reader_.ReadLine(&line));
+ EXPECT_TRUE(reader_.Open(path));
+ for (size_t i = 0; i < lines.size(); ++i) {
+ EXPECT_TRUE(reader_.ReadLine(&line));
+ EXPECT_EQ(lines[i], line);
+ }
+ EXPECT_FALSE(reader_.ReadLine(&line));
+ reader_.Close();
+ EXPECT_FALSE(reader_.ReadLine(&line));
+ }
+
+ protected:
+ FileReader reader_;
+};
+
+TEST_F(FileReaderTest, OpenNonExistentFile) {
+ EXPECT_FALSE(reader_.Open(FilePath("a_nonexistent_file")));
+}
+
+TEST_F(FileReaderTest, OpenEmptyFile) {
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath path;
+ ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir.path(), &path));
+
+ EXPECT_TRUE(reader_.Open(path));
+ string line;
+ EXPECT_FALSE(reader_.ReadLine(&line));
+ reader_.Close();
+}
+
+TEST_F(FileReaderTest, ReadLine) {
+ vector<string> lines;
+ lines.push_back("this is");
+ lines.push_back("a");
+ lines.push_back("");
+ lines.push_back("test");
+ string content = JoinString(lines, '\n');
+
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath path;
+ ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir.path(), &path));
+
+ // Test a file not ending with a new-line character
+ ASSERT_EQ(content.size(),
+ file_util::WriteFile(path, content.c_str(), content.size()));
+ VerifyReadLines(path, lines);
+
+ // Test a file ending with a new-line character
+ content.push_back('\n');
+ ASSERT_EQ(content.size(),
+ file_util::WriteFile(path, content.c_str(), content.size()));
+ VerifyReadLines(path, lines);
+}
+
+} // namespace shill
diff --git a/mock_cellular_operator_info.cc b/mock_cellular_operator_info.cc
index f5cc5ca..8a9f336 100644
--- a/mock_cellular_operator_info.cc
+++ b/mock_cellular_operator_info.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2013 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.
@@ -7,7 +7,7 @@
namespace shill {
MockCellularOperatorInfo::MockCellularOperatorInfo()
- : CellularOperatorInfo(NULL) {}
+ : CellularOperatorInfo() {}
MockCellularOperatorInfo::~MockCellularOperatorInfo() {}
diff --git a/mock_cellular_operator_info.h b/mock_cellular_operator_info.h
index 2acb0db..9346301 100644
--- a/mock_cellular_operator_info.h
+++ b/mock_cellular_operator_info.h
@@ -19,8 +19,8 @@
virtual ~MockCellularOperatorInfo();
MOCK_METHOD1(Load, bool(const FilePath &info_file_path));
- MOCK_METHOD2(GetOLP, bool(const std::string &operator_id,
- CellularService::OLP *olp));
+ MOCK_METHOD1(GetOLPByMCCMNC,
+ const CellularService::OLP *(const std::string &operator_id));
};
} // namespace shill
diff --git a/modem_info.cc b/modem_info.cc
index e6d0139..8888e60 100644
--- a/modem_info.cc
+++ b/modem_info.cc
@@ -52,7 +52,7 @@
}
void ModemInfo::Start() {
- cellular_operator_info_.reset(new CellularOperatorInfo(glib_));
+ cellular_operator_info_.reset(new CellularOperatorInfo());
cellular_operator_info_->Load(FilePath(kCellularOperatorInfoPath));
// TODO(petkov): Consider initializing the mobile provider database lazily