shill: separate (externally observed) failure state from internal
failure condition.

Changing a service's state to failure causes Chrome to display
a connection failed dialog. Consequently, before this CL, if
a user suspends a device at home, and resumes it at the office,
he'll see a spurious connection failure dialog. (shill will
display the dialog when it can't connect to the home AP, even
though it is about to connect to the office AP.)

To resolve this, we set a WiFiService's state to idle, rather
than failure. However, internally, we record the time at which
the service disconnected, and use that to determine whether or
not a service is failed.

BUG=chromium-os:26828
TEST=new unit tests

Change-Id: I556a110f5705495d681f40c1bb645c34bd0e43f9
Reviewed-on: https://gerrit.chromium.org/gerrit/18685
Commit-Ready: mukesh agrawal <quiche@chromium.org>
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Tested-by: mukesh agrawal <quiche@chromium.org>
diff --git a/service_unittest.cc b/service_unittest.cc
index c28741e..03a3fac 100644
--- a/service_unittest.cc
+++ b/service_unittest.cc
@@ -263,17 +263,30 @@
   service_->SetState(Service::kStateConnected);
   // A second state change shouldn't cause another update
   service_->SetState(Service::kStateConnected);
-
   EXPECT_EQ(Service::kStateConnected, service_->state());
   EXPECT_EQ(Service::kFailureUnknown, service_->failure());
+
   EXPECT_CALL(mock_manager_, UpdateService(service_ref));
   service_->SetState(Service::kStateDisconnected);
 
   EXPECT_CALL(mock_manager_, UpdateService(service_ref));
   service_->SetFailure(Service::kFailureOutOfRange);
-
+  EXPECT_TRUE(service_->IsFailed());
+  EXPECT_GT(service_->failed_time_, 0);
   EXPECT_EQ(Service::kStateFailure, service_->state());
   EXPECT_EQ(Service::kFailureOutOfRange, service_->failure());
+
+  EXPECT_CALL(mock_manager_, UpdateService(service_ref));
+  service_->SetState(Service::kStateConnected);
+  EXPECT_FALSE(service_->IsFailed());
+  EXPECT_EQ(service_->failed_time_, 0);
+
+  EXPECT_CALL(mock_manager_, UpdateService(service_ref));
+  service_->SetFailureSilent(Service::kFailurePinMissing);
+  EXPECT_TRUE(service_->IsFailed());
+  EXPECT_GT(service_->failed_time_, 0);
+  EXPECT_EQ(Service::kStateIdle, service_->state());
+  EXPECT_EQ(Service::kFailurePinMissing, service_->failure());
 }
 
 TEST_F(ServiceTest, ActivateCellularModem) {