shill: WiFiService overrides generic Service Load/Save

As a side effect, I worked on storage-names for WPA/RSN networks
mapping to PSK, and implemented rudimentary loading of the
"hidden_ssid_" property.

BUG=chromium-os:17255,chromium-os:20899,chromium-os:21293
TEST=Run Unittests

Change-Id: Id7459f41f3940160827f42d7c3d13c00c67f85fe
Reviewed-on: https://gerrit.chromium.org/gerrit/11226
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
Commit-Ready: Paul Stewart <pstew@chromium.org>
diff --git a/wifi_service_unittest.cc b/wifi_service_unittest.cc
index ab3844f..6533fa1 100644
--- a/wifi_service_unittest.cc
+++ b/wifi_service_unittest.cc
@@ -28,7 +28,12 @@
 using std::vector;
 
 namespace shill {
+using ::testing::_;
+using ::testing::DoAll;
 using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::SetArgumentPointee;
+using ::testing::StrEq;
 
 class WiFiServiceTest : public PropertyStoreTest {
  public:
@@ -53,6 +58,72 @@
 // static
 const char WiFiServiceTest::fake_mac[] = "AaBBcCDDeeFF";
 
+class WiFiServiceSecurityTest : public WiFiServiceTest {
+ public:
+  WiFiServiceRefPtr CreateServiceWithSecurity(const string &security) {
+    vector<uint8_t> ssid(5, 0);
+    ssid.push_back(0xff);
+
+    return new WiFiService(control_interface(),
+                           dispatcher(),
+                           manager(),
+                           wifi(),
+                           ssid,
+                           flimflam::kModeManaged,
+                           security);
+  }
+
+  bool TestStorageSecurityIs(WiFiServiceRefPtr wifi_service,
+                             const string &security) {
+    string id = wifi_service->GetStorageIdentifier();
+    size_t mac_pos = id.find(StringToLowerASCII(string(fake_mac)));
+    EXPECT_NE(mac_pos, string::npos);
+    size_t mode_pos = id.find(string(flimflam::kModeManaged), mac_pos);
+    EXPECT_NE(mode_pos, string::npos);
+    return id.find(string(security), mode_pos) != string::npos;
+  }
+
+  // Test that a service that is created with security |from_security|
+  // gets by default a storage identifier with |to_security| as its
+  // security component.
+  bool TestStorageMapping(const string &from_security,
+                          const string &to_security) {
+    WiFiServiceRefPtr wifi_service = CreateServiceWithSecurity(from_security);
+    return TestStorageSecurityIs(wifi_service, to_security);
+  }
+
+  // Test whether a service of type |service_security| can load from a
+  // storage interface containing an entry for |storage_security|.
+  // Make sure the result meets |expectation|.  If |expectation| is
+  // true, also make sure the service storage identifier changes to
+  // match |storage_security|.
+  bool TestLoadMapping(const string &service_security,
+                       const string &storage_security,
+                       bool expectation) {
+    WiFiServiceRefPtr wifi_service =
+        CreateServiceWithSecurity(service_security);
+    NiceMock<MockStore> mock_store;
+    const string storage_id =
+        wifi_service->GetStorageIdentifierForSecurity(storage_security);
+    EXPECT_CALL(mock_store, ContainsGroup(_))
+        .WillRepeatedly(Return(false));
+    EXPECT_CALL(mock_store, ContainsGroup(StrEq(storage_id)))
+        .WillRepeatedly(Return(true));
+    bool is_loadable = wifi_service->IsLoadableFrom(&mock_store);
+    EXPECT_EQ(expectation, is_loadable);
+    bool is_loaded = wifi_service->Load(&mock_store);
+    EXPECT_EQ(expectation, is_loaded);
+
+    if (expectation != is_loadable || expectation != is_loaded) {
+      return false;
+    } else if (!expectation) {
+      return true;
+    } else {
+      return TestStorageSecurityIs(wifi_service, storage_security);
+    }
+  }
+};
+
 MATCHER(WPASecurityArgs, "") {
   return ContainsKey(arg, wpa_supplicant::kPropertySecurityProtocol) &&
       ContainsKey(arg, wpa_supplicant::kPropertyPreSharedKey);
@@ -68,7 +139,7 @@
                                                    wifi(),
                                                    ssid,
                                                    flimflam::kModeManaged,
-                                                   "none");
+                                                   flimflam::kSecurityNone);
   string id = wifi_service->GetStorageIdentifier();
   for (uint i = 0; i < id.length(); ++i) {
     EXPECT_TRUE(id[i] == '_' ||
@@ -91,7 +162,7 @@
                                                    wifi(),
                                                    ssid,
                                                    flimflam::kModeManaged,
-                                                   "none");
+                                                   flimflam::kSecurityNone);
   map<string, ::DBus::Variant> properties;
   // if service doesn't propertly sanitize SSID, this will generate SIGABRT.
   DBusAdaptor::GetProperties(wifi_service->store(), &properties, NULL);
@@ -125,4 +196,72 @@
   wifi_service->ConnectTask();
 }
 
+TEST_F(WiFiServiceTest, LoadHidden) {
+  vector<uint8_t> ssid(5, 0);
+  ssid.push_back(0xff);
+
+  WiFiServiceRefPtr service = new WiFiService(control_interface(),
+                                              dispatcher(),
+                                              manager(),
+                                              wifi(),
+                                              ssid,
+                                              flimflam::kModeManaged,
+                                              flimflam::kSecurityNone);
+  ASSERT_FALSE(service->hidden_ssid_);
+  NiceMock<MockStore> mock_store;
+  const string storage_id = service->GetStorageIdentifier();
+  EXPECT_CALL(mock_store, ContainsGroup(StrEq(storage_id)))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(mock_store, GetBool(_, _, _))
+      .WillRepeatedly(Return(false));
+  EXPECT_CALL(mock_store,
+              GetBool(StrEq(storage_id), WiFiService::kStorageHiddenSSID, _))
+      .WillRepeatedly(DoAll(SetArgumentPointee<2>(true), Return(true)));
+  EXPECT_TRUE(service->Load(&mock_store));
+  EXPECT_TRUE(service->hidden_ssid_);
+}
+
+TEST_F(WiFiServiceSecurityTest, WPAMapping) {
+  EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityRsn,
+                                 flimflam::kSecurityPsk));
+  EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityWpa,
+                                 flimflam::kSecurityPsk));
+  EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityPsk,
+                                 flimflam::kSecurityPsk));
+  EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityWep,
+                                 flimflam::kSecurityWep));
+  EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityNone,
+                                 flimflam::kSecurityNone));
+  // TODO(pstew): 802.1x is in a NOTIMPLEMENTED block in wifi_service.cc
+  // EXPECT_TRUE(TestStorageMapping(flimflam::kSecurity8021x,
+  //                                flimflam::kSecurity8021x));
+}
+
+TEST_F(WiFiServiceSecurityTest, LoadMapping) {
+  EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityRsn,
+                              flimflam::kSecurityPsk,
+                              true));
+  EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityRsn,
+                              flimflam::kSecurityRsn,
+                              true));
+  EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityRsn,
+                              flimflam::kSecurityWpa,
+                              false));
+  EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWpa,
+                              flimflam::kSecurityPsk,
+                              true));
+  EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWpa,
+                              flimflam::kSecurityWpa,
+                              true));
+  EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWpa,
+                              flimflam::kSecurityRsn,
+                              false));
+  EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWep,
+                              flimflam::kSecurityWep,
+                              true));
+  EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWep,
+                              flimflam::kSecurityPsk,
+                              false));
+}
+
 }  // namespace shill