autotest: Make interop tests work on WpaCliProxy hosts

Since wpa_cli hosts don't have profiles, we can't manipulate profiles to
create a clean test context.  Add a method init_test_network_state which
abstracts these details into platform specific operations.

The shill XMLRPC delegate simply returns False when it is unable to
disconnect from a given ssid.  WpaCliProxy should do likewise rather
than complaining about missing keys in its created networks list.

TEST=Interop tests work against WpaCliProxy based hosts.
check11b still passes on a normal host.
BUG=chromium:302855

Change-Id: I5886df8154f46e3e1b43b325d2ac1a857cbaebc2
Reviewed-on: https://chromium-review.googlesource.com/171923
Tested-by: Christopher Wiley <wiley@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Commit-Queue: Christopher Wiley <wiley@chromium.org>
diff --git a/client/common_lib/cros/network/shill_xmlrpc_server.py b/client/common_lib/cros/network/shill_xmlrpc_server.py
index e8b06f8..aa7a032 100755
--- a/client/common_lib/cros/network/shill_xmlrpc_server.py
+++ b/client/common_lib/cros/network/shill_xmlrpc_server.py
@@ -33,6 +33,9 @@
 
     """
 
+    DEFAULT_TEST_PROFILE_NAME = 'test'
+
+
     def __init__(self):
         self._wifi_proxy = wifi_proxy.WifiProxy()
         self._tpm_store = tpm_store.TPMStore()
@@ -143,6 +146,27 @@
         return result
 
 
+    def init_test_network_state(self):
+        """Create a clean slate for tests with respect to remembered networks.
+
+        For shill, this means popping and removing profiles before adding a
+        'test' profile.
+
+        @return True iff operation succeeded, False otherwise.
+
+        """
+        # TODO(wiley) We've not seen this problem before, but there could
+        #             still be remembered networks in the default profile.
+        #             at the very least, this profile has the ethernet
+        #             entry.
+        self.clean_profiles()
+        self.remove_profile(self.DEFAULT_TEST_PROFILE_NAME)
+        worked = self.create_profile(self.DEFAULT_TEST_PROFILE_NAME)
+        if worked:
+            worked = self.push_profile(self.DEFAULT_TEST_PROFILE_NAME)
+        return worked
+
+
     @xmlrpc_server.dbus_safe(False)
     def disconnect(self, ssid):
         """Attempt to disconnect from the given ssid.
diff --git a/server/cros/chaos_lib/chaos_base_test.py b/server/cros/chaos_lib/chaos_base_test.py
index 6482b26..e26be59 100644
--- a/server/cros/chaos_lib/chaos_base_test.py
+++ b/server/cros/chaos_lib/chaos_base_test.py
@@ -82,11 +82,7 @@
 
         """
         self.client.shill.disconnect(ap_info['ssid'])
-        self.client.shill.clean_profiles()
-        # Be extra sure that we're going to push successfully.
-        self.client.shill.remove_profile(self.TEST_PROFILE_NAME)
-        if (not self.client.shill.create_profile(self.TEST_PROFILE_NAME) or
-                not self.client.shill.push_profile(self.TEST_PROFILE_NAME)):
+        if not self.client.shill.init_test_network_state():
             return 'Failed to set up isolated test context profile.'
 
         # TODO(wiley) We probably don't always want HT40, but
diff --git a/server/cros/network/wifi_test_context_manager.py b/server/cros/network/wifi_test_context_manager.py
index 1315c0e..b0ef08d 100644
--- a/server/cros/network/wifi_test_context_manager.py
+++ b/server/cros/network/wifi_test_context_manager.py
@@ -199,13 +199,8 @@
         # services, such as OpenVPN or StrongSwan.
         server_host = hosts.SSHHost(self.server_address, port=22)
         self._server = site_linux_server.LinuxServer(server_host, {})
-        # Set up a test profile on a clean stack.
-        self.client.shill.clean_profiles()
-        # This extra remove takes care of a case where we popped the test
-        # profile in a previous test, but crashed before we removed it.
-        self.client.shill.remove_profile('test')
-        self.client.shill.create_profile('test')
-        self.client.shill.push_profile('test')
+        # Set up a clean context to conduct WiFi tests in.
+        self.client.shill.init_test_network_state()
         if self.CMDLINE_CLIENT_PACKET_CAPTURES in self._cmdline_args:
             self._enable_client_packet_captures = True
         if self.CMDLINE_ROUTER_PACKET_CAPTURES in self._cmdline_args:
diff --git a/server/cros/network/wpa_cli_proxy.py b/server/cros/network/wpa_cli_proxy.py
index 82f2957..7e0edaf 100644
--- a/server/cros/network/wpa_cli_proxy.py
+++ b/server/cros/network/wpa_cli_proxy.py
@@ -159,6 +159,18 @@
         logging.info('Skipping remove_profile on %s', self.__class__.__name__)
 
 
+    def init_test_network_state(self):
+        """Create a clean slate for tests with respect to remembered networks.
+
+        For wpa_cli hosts, this means removing all remembered networks.
+
+        @return True iff operation succeeded, False otherwise.
+
+        """
+        self.clean_profiles()
+        return True
+
+
     def connect_wifi(self, assoc_params):
         """
         Connect to the WiFi network described by AssociationParameters.
@@ -245,6 +257,7 @@
             return assoc_result.serialize()
 
         assoc_result.success = True
+        logging.info('Connected to %s', assoc_params.ssid)
         return assoc_result.serialize()
 
 
@@ -256,8 +269,11 @@
 
         """
         logging.debug('disconnect()')
+        if ssid not in self._created_networks:
+            return False
         self._run_wpa_cli_cmd('disable_network %d' %
                               self._created_networks[ssid])
+        return True
 
 
     def sync_time_to(self, epoch_seconds):