shill: Make cellular Connect work for GSM networks.

Add the APN to the properties map passed to Connect.
Set up the list of APNs to try, and step through it when
a connect attempt fails with the InvalidApn error. The
order in which APNs are tried is

  - APN which most recently resulted in a successful
    connection on the current network
  - a user-specified APN, specified by setting the Cellular.APN
    property on the service
  - the list of APNs found for the home network provider in the
    mobile broadband provider database
  - if all those fail, a null APN

BUG=chromium-os:23259
TEST=manual testing, some of which involved modifying the
mobile provider DB to create invalid APN entries. Created
two new unit tests as well, and ran all unit tests.

Change-Id: I38c869228fe1aaf7421de8a826c54e7b62c209b2
Reviewed-on: https://gerrit.chromium.org/gerrit/19122
Tested-by: Eric Shienbrood <ers@chromium.org>
Reviewed-by: Jason Glasgow <jglasgow@chromium.org>
Commit-Ready: Eric Shienbrood <ers@chromium.org>
diff --git a/cellular_capability_gsm_unittest.cc b/cellular_capability_gsm_unittest.cc
index 5083736..c516ee9 100644
--- a/cellular_capability_gsm_unittest.cc
+++ b/cellular_capability_gsm_unittest.cc
@@ -18,6 +18,7 @@
 #include "shill/mock_metrics.h"
 #include "shill/mock_modem_gsm_card_proxy.h"
 #include "shill/mock_modem_gsm_network_proxy.h"
+#include "shill/mock_profile.h"
 #include "shill/nice_mock_control.h"
 
 using base::Bind;
@@ -617,4 +618,71 @@
   EXPECT_EQ(kRetries, capability_->sim_lock_status_.retries_left);
 }
 
+TEST_F(CellularCapabilityGSMTest, SetupApnTryList) {
+  static const string kTmobileApn("epc.tmobile.com");
+  static const string kLastGoodApn("remembered.apn");
+  static const string kLastGoodUsername("remembered.user");
+  static const string kSuppliedApn("my.apn");
+
+  SetService();
+  capability_->imsi_ = "310240123456789";
+  InitProviderDB();
+  capability_->SetHomeProvider();
+  DBusPropertiesMap props;
+  capability_->SetupConnectProperties(&props);
+  EXPECT_FALSE(props.find(flimflam::kApnProperty) == props.end());
+  EXPECT_EQ(kTmobileApn, props[flimflam::kApnProperty].reader().get_string());
+
+  ProfileRefPtr profile(new NiceMock<MockProfile>(
+      &control_, reinterpret_cast<Manager *>(NULL)));
+  cellular_->service()->set_profile(profile);
+  Stringmap apn_info;
+  apn_info[flimflam::kApnProperty] = kLastGoodApn;
+  apn_info[flimflam::kApnUsernameProperty] = kLastGoodUsername;
+  cellular_->service()->SetLastGoodApn(apn_info);
+  props.clear();
+  EXPECT_TRUE(props.find(flimflam::kApnProperty) == props.end());
+  capability_->SetupConnectProperties(&props);
+  // We expect the list to contain the last good APN, plus
+  // the 4 APNs from the mobile provider info database.
+  EXPECT_EQ(5, capability_->apn_try_list_.size());
+  EXPECT_FALSE(props.find(flimflam::kApnProperty) == props.end());
+  EXPECT_EQ(kLastGoodApn, props[flimflam::kApnProperty].reader().get_string());
+  EXPECT_FALSE(props.find(flimflam::kApnUsernameProperty) == props.end());
+  EXPECT_EQ(kLastGoodUsername,
+            props[flimflam::kApnUsernameProperty].reader().get_string());
+
+  Error error;
+  apn_info.clear();
+  props.clear();
+  apn_info[flimflam::kApnProperty] = kSuppliedApn;
+  // Setting the APN has the side effect of clearing the LastGoodApn,
+  // so the try list will have 5 elements, with the first one being
+  // the supplied APN.
+  cellular_->service()->SetApn(apn_info, &error);
+  EXPECT_TRUE(props.find(flimflam::kApnProperty) == props.end());
+  capability_->SetupConnectProperties(&props);
+  EXPECT_EQ(5, capability_->apn_try_list_.size());
+  EXPECT_FALSE(props.find(flimflam::kApnProperty) == props.end());
+  EXPECT_EQ(kSuppliedApn, props[flimflam::kApnProperty].reader().get_string());
+
+  apn_info.clear();
+  props.clear();
+  apn_info[flimflam::kApnProperty] = kLastGoodApn;
+  apn_info[flimflam::kApnUsernameProperty] = kLastGoodUsername;
+  // Now when LastGoodAPN is set, it will be the one selected.
+  cellular_->service()->SetLastGoodApn(apn_info);
+  EXPECT_TRUE(props.find(flimflam::kApnProperty) == props.end());
+  capability_->SetupConnectProperties(&props);
+  // We expect the list to contain the last good APN, plus
+  // the user-supplied APN, plus the 4 APNs from the mobile
+  // provider info database.
+  EXPECT_EQ(6, capability_->apn_try_list_.size());
+  EXPECT_FALSE(props.find(flimflam::kApnProperty) == props.end());
+  EXPECT_EQ(kLastGoodApn, props[flimflam::kApnProperty].reader().get_string());
+  EXPECT_FALSE(props.find(flimflam::kApnUsernameProperty) == props.end());
+  EXPECT_EQ(kLastGoodUsername,
+            props[flimflam::kApnUsernameProperty].reader().get_string());
+}
+
 }  // namespace shill