shill: Call OnPropertyChanged() for properties changed via Configure()

For wifi services on enterprise enrolled devices, credentials might be
pushed down asynchronously rather than entered by the user.  This
reveals that we don't update whether a network is connectable when
credentials arrive and are set via Service::Configure().

BUG=chromium-os:35774
TEST=Unit tests, wrote a new one

Change-Id: I60215a89c3991b4ce8035f730c790187e6ccc087
Reviewed-on: https://gerrit.chromium.org/gerrit/37304
Tested-by: Christopher Wiley <wiley@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Commit-Ready: Christopher Wiley <wiley@chromium.org>
diff --git a/service.cc b/service.cc
index c327a33..2394515 100644
--- a/service.cc
+++ b/service.cc
@@ -472,6 +472,7 @@
     SLOG(Service, 5) << "   " << bool_it->first;
     Error set_error;
     store_.SetBoolProperty(bool_it->first, bool_it->second, &set_error);
+    OnPropertyChanged(bool_it->first);
     if (error->IsSuccess() && set_error.IsFailure()) {
       error->CopyFrom(set_error);
     }
@@ -487,6 +488,7 @@
     SLOG(Service, 5) << "   " << string_it->first;
     Error set_error;
     store_.SetStringProperty(string_it->first, string_it->second, &set_error);
+    OnPropertyChanged(string_it->first);
     if (error->IsSuccess() && set_error.IsFailure()) {
       error->CopyFrom(set_error);
     }
@@ -502,6 +504,7 @@
     SLOG(Service, 5) << "   " << int_it->first;
     Error set_error;
     store_.SetUint32Property(int_it->first, int_it->second, &set_error);
+    OnPropertyChanged(int_it->first);
     if (error->IsSuccess() && set_error.IsFailure()) {
       error->CopyFrom(set_error);
     }
diff --git a/wifi_service_unittest.cc b/wifi_service_unittest.cc
index 0bba7f4..c69265d 100644
--- a/wifi_service_unittest.cc
+++ b/wifi_service_unittest.cc
@@ -719,6 +719,36 @@
   EXPECT_TRUE(service->need_passphrase_);
 }
 
+TEST_F(WiFiServiceTest, ConfigureMakesConnectable) {
+  string guid("legit_guid");
+  KeyValueStore args;
+  args.SetString(flimflam::kEapIdentityProperty, "legit_identity");
+  args.SetString(flimflam::kEapPasswordProperty, "legit_password");
+  args.SetString(flimflam::kEAPEAPProperty, "PEAP");
+  args.SetString(flimflam::kGuidProperty, guid);
+  Error error;
+  vector<uint8_t> ssid(5);
+  ssid.push_back(0xff);
+
+  WiFiServiceRefPtr service = new WiFiService(control_interface(),
+                                              dispatcher(),
+                                              metrics(),
+                                              manager(),
+                                              wifi(),
+                                              ssid,
+                                              flimflam::kModeManaged,
+                                              flimflam::kSecurity8021x,
+                                              false);
+  // Hack the GUID in so that we don't have to mess about with WiFi to regsiter
+  // our service.  This way, Manager will handle the lookup itself.
+  service->set_guid(guid);
+  manager()->RegisterService(service);
+  EXPECT_FALSE(service->connectable());
+  EXPECT_EQ(service.get(), manager()->GetService(args, &error).get());
+  EXPECT_TRUE(error.IsSuccess());
+  EXPECT_TRUE(service->connectable());
+}
+
 TEST_F(WiFiServiceTest, UnloadAndClearCacheWep) {
   vector<uint8_t> ssid(1, 'a');
   WiFiServiceRefPtr service = new WiFiService(control_interface(),