shill: Only reset service state before connect if it had failed priorly.

BUG=chromium:213956
TEST=New unit tests, network_3GSafetyDance

Change-Id: I1227cd00df9105606d8056ca5b6bb5e2882a4f6f
Reviewed-on: https://gerrit.chromium.org/gerrit/60263
Reviewed-by: Arman Uguray <armansito@chromium.org>
Commit-Queue: Thieu Le <thieule@chromium.org>
Tested-by: Thieu Le <thieule@chromium.org>
diff --git a/service.cc b/service.cc
index 54a3d55..5cf545e 100644
--- a/service.cc
+++ b/service.cc
@@ -245,8 +245,9 @@
 void Service::Connect(Error */*error*/, const char *reason) {
   LOG(INFO) << "Connect to service " << unique_name() <<": " << reason;
   explicitly_disconnected_ = false;
-  // clear any failure state from a previous connect attempt
-  SetState(kStateIdle);
+  // Clear any failure state from a previous connect attempt.
+  if (state() == kStateFailure)
+    SetState(kStateIdle);
 }
 
 void Service::Disconnect(Error */*error*/) {
diff --git a/service.h b/service.h
index 9297618..bf35c69 100644
--- a/service.h
+++ b/service.h
@@ -578,6 +578,7 @@
   FRIEND_TEST(ServiceTest, SetFriendlyName);
   FRIEND_TEST(ServiceTest, SetProperty);
   FRIEND_TEST(ServiceTest, State);
+  FRIEND_TEST(ServiceTest, StateResetAfterFailure);
   FRIEND_TEST(ServiceTest, Unload);
   FRIEND_TEST(WiFiMainTest, SuspectCredentialsEAPInProgress);
   FRIEND_TEST(WiFiMainTest, SuspectCredentialsWPAPreviouslyConnected);
diff --git a/service_unittest.cc b/service_unittest.cc
index c5c6c28..f0dd01a 100644
--- a/service_unittest.cc
+++ b/service_unittest.cc
@@ -571,6 +571,19 @@
   service_->set_profile(NULL);  // Break reference cycle.
 }
 
+TEST_F(ServiceTest, StateResetAfterFailure) {
+  service_->SetFailure(Service::kFailureOutOfRange);
+  EXPECT_EQ(Service::kStateFailure, service_->state());
+  Error error;
+  service_->Connect(&error, "in test");
+  EXPECT_EQ(Service::kStateIdle, service_->state());
+  EXPECT_EQ(Service::kFailureUnknown, service_->failure());
+
+  service_->SetState(Service::kStateConnected);
+  service_->Connect(&error, "in test");
+  EXPECT_EQ(Service::kStateConnected, service_->state());
+}
+
 TEST_F(ServiceTest, ActivateCellularModem) {
   ResultCallback callback =
       Bind(&ServiceTest::TestCallback, Unretained(this));