autotest (wifi): reduce flake in network_WiFi_ConnectionIdentifier

In some trials of network_WiFi_ConnectionIdentifier, we
see that the ID is zero. This is probably due to a race
condition.

Specifically: we attempt to read the connection
ID when assert_connect_wifi() returns. But I don't believe
that there is any guarantee that ActiveLinkMonitor has
successfully ARPed the gateway at this point.

To address this race, we poll the service properties until
ConnectionId is non-zero (or until we time out).

BUG=chromium:502522
TEST=network_WiFi_ConnectionIdentifier (10 iterations)

Of the 10 iterations, 8 passed. The two failures were for other
reasons. (I.e., none of the failures were due to "Connection
ID mismatched".)

Change-Id: I17afab31ff25c021e56f2991588728cdececad45
Reviewed-on: https://chromium-review.googlesource.com/280901
Reviewed-by: Paul Stewart <pstew@chromium.org>
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Tested-by: mukesh agrawal <quiche@chromium.org>
Commit-Queue: mukesh agrawal <quiche@chromium.org>
Trybot-Ready: mukesh agrawal <quiche@chromium.org>
diff --git a/server/site_tests/network_WiFi_ConnectionIdentifier/network_WiFi_ConnectionIdentifier.py b/server/site_tests/network_WiFi_ConnectionIdentifier/network_WiFi_ConnectionIdentifier.py
index 6f86e86..cdea836 100644
--- a/server/site_tests/network_WiFi_ConnectionIdentifier/network_WiFi_ConnectionIdentifier.py
+++ b/server/site_tests/network_WiFi_ConnectionIdentifier/network_WiFi_ConnectionIdentifier.py
@@ -2,6 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import logging
+import time
+
 from autotest_lib.client.common_lib import error
 from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes
 from autotest_lib.server.cros.network import hostap_config
@@ -12,8 +15,30 @@
     """Test for verifying connection identifier."""
     version = 1
 
+    CONNECTION_ID_TIMEOUT_SECS = 10
     SERVICE_PROPERTY_CONNECTION_ID = 'ConnectionId'
 
+    def _get_service_connection_id(self, ssid):
+        """Get the connection ID for a service.
+
+        Polls a service's properties until ConnectionId becomes non-zero,
+        or a timeout occurs.
+
+        @param ssid: SSID of the service of interest.
+        @raise TestError if a timeout occurs.
+        @return ConnectionId of the current service.
+        """
+        start_time = time.time()
+        while time.time() - start_time < self.CONNECTION_ID_TIMEOUT_SECS:
+            properties = self.context.client.shill.get_service_properties(ssid)
+            logging.debug('Service properties are: %s', properties)
+            connection_id = properties[self.SERVICE_PROPERTY_CONNECTION_ID]
+            if connection_id != 0:
+                return connection_id
+            time.sleep(1)
+        raise error.TestFail('ConnectionId remained zero')
+
+
     def _connect(self, ssid, expected_connection_id=None):
         """Connect to an AP, and verify connection ID if it is specified.
 
@@ -23,11 +48,12 @@
         """
         client_conf = xmlrpc_datatypes.AssociationParameters(ssid)
         self.context.assert_connect_wifi(client_conf)
-        properties = self.context.client.shill.get_service_properties(ssid)
-        connection_id = properties[self.SERVICE_PROPERTY_CONNECTION_ID]
+        connection_id = self._get_service_connection_id(ssid)
         if (expected_connection_id is not None and
                 expected_connection_id != connection_id):
-            raise error.TestFail('Connection ID mismatched')
+            raise error.TestFail(
+              'Expected connection ID %s, but got %s' % (
+                expected_connection_id, connection_id))
         return connection_id