shill: Refuse to connect already connect[ed|ing] WiFi services

Don't let users crash shill by requesting to connect to WiFi services
we've already connected to or are connecting to.

BUG=chromium-os:34656
TEST=Unit tests

Change-Id: I5f7802a8b67f3a460d4f9ffd97bb00e126e2e366
Reviewed-on: https://gerrit.chromium.org/gerrit/35073
Reviewed-by: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
Commit-Ready: Christopher Wiley <wiley@chromium.org>
Tested-by: Christopher Wiley <wiley@chromium.org>
diff --git a/wifi_service_unittest.cc b/wifi_service_unittest.cc
index e1340ed..0bba7f4 100644
--- a/wifi_service_unittest.cc
+++ b/wifi_service_unittest.cc
@@ -18,6 +18,7 @@
 #include "shill/mock_adaptors.h"
 #include "shill/mock_control.h"
 #include "shill/mock_nss.h"
+#include "shill/mock_profile.h"
 #include "shill/mock_service.h"
 #include "shill/mock_store.h"
 #include "shill/mock_wifi.h"
@@ -372,6 +373,43 @@
   wifi_service->Connect(NULL);
 }
 
+TEST_F(WiFiServiceTest, ConnectConditions) {
+  Error error;
+  vector<uint8_t> ssid(5);
+  WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
+                                                   dispatcher(),
+                                                   metrics(),
+                                                   manager(),
+                                                   wifi(),
+                                                   ssid,
+                                                   flimflam::kModeManaged,
+                                                   flimflam::kSecurityNone,
+                                                   false);
+  scoped_refptr<MockProfile> mock_profile(
+      new NiceMock<MockProfile>(control_interface(), manager()));
+  wifi_service->set_profile(mock_profile);
+  // With nothing else going on, the service should attempt to connect.
+  EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get(), _));
+  wifi_service->Connect(&error);
+  Mock::VerifyAndClearExpectations(wifi());
+
+  // But if we're already "connecting" or "connected" then we shouldn't attempt
+  // again.
+  EXPECT_CALL(*wifi(),
+              ConnectTo(wifi_service.get(), _)).Times(0);
+  wifi_service->SetState(Service::kStateAssociating);
+  wifi_service->Connect(&error);
+  wifi_service->SetState(Service::kStateConfiguring);
+  wifi_service->Connect(&error);
+  wifi_service->SetState(Service::kStateConnected);
+  wifi_service->Connect(&error);
+  wifi_service->SetState(Service::kStatePortal);
+  wifi_service->Connect(&error);
+  wifi_service->SetState(Service::kStateOnline);
+  wifi_service->Connect(&error);
+  Mock::VerifyAndClearExpectations(wifi());
+}
+
 TEST_F(WiFiServiceTest, ConnectTaskPSK) {
   vector<uint8_t> ssid(5);
   WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),