bluetooth: merge duplicate update_btpeers functions

bluetooth_PeerUpdate test has many duplicate logic also implemented in
bluetooth_peer_update, merge them into a new function, update_btpeers.

BUG=b:222050857
TEST=test_that bluetooth_PeerUpdate

Change-Id: Id220a2de8a0499a772516afb0ab5f9065e5c92bb
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/3498132
Reviewed-by: Shyh-In Hwang <josephsih@chromium.org>
Reviewed-by: Shuo-Peng Liao <deanliao@chromium.org>
Reviewed-by: Shijin Abraham <shijinabraham@google.com>
Commit-Queue: John Lai <johnlai@google.com>
Tested-by: John Lai <johnlai@google.com>
diff --git a/server/cros/bluetooth/bluetooth_adapter_quick_tests.py b/server/cros/bluetooth/bluetooth_adapter_quick_tests.py
index c653f09..8879d27 100644
--- a/server/cros/bluetooth/bluetooth_adapter_quick_tests.py
+++ b/server/cros/bluetooth/bluetooth_adapter_quick_tests.py
@@ -21,6 +21,7 @@
 import common
 from autotest_lib.client.common_lib import error
 from autotest_lib.server import site_utils
+from autotest_lib.server.cros.bluetooth import bluetooth_peer_update
 from autotest_lib.server.cros.bluetooth import bluetooth_adapter_tests
 from autotest_lib.server.cros.bluetooth import bluetooth_attenuator
 from autotest_lib.server.cros.multimedia import remote_facade_factory
@@ -201,7 +202,7 @@
 
             # Check the chameleond version on the peer and update if necessary
             if update_btpeers:
-                if not self.update_btpeer():
+                if not bluetooth_peer_update.update_all_peers(self.host):
                     logging.error('Updating btpeers failed. Ignored')
             else:
                 logging.info('No attempting peer update.')
diff --git a/server/cros/bluetooth/bluetooth_adapter_tests.py b/server/cros/bluetooth/bluetooth_adapter_tests.py
index dfbe961..90f733b 100644
--- a/server/cros/bluetooth/bluetooth_adapter_tests.py
+++ b/server/cros/bluetooth/bluetooth_adapter_tests.py
@@ -28,7 +28,6 @@
 from autotest_lib.client.common_lib import error
 from autotest_lib.client.common_lib.cros.bluetooth import bluetooth_socket
 from autotest_lib.client.cros.chameleon import chameleon
-from autotest_lib.server.cros.bluetooth import bluetooth_peer_update
 from autotest_lib.server.cros.bluetooth import bluetooth_test_utils
 from autotest_lib.server import test
 
@@ -4806,70 +4805,6 @@
         self.count_advertisements = 0
 
 
-    def update_btpeer(self):
-        """ Check and update the chameleond bundle on Bluetooth peer
-        Latest chameleond bundle and git commit is stored in the google cloud
-        This function compares the git commit of the Bluetooth peers and update
-        the peer if the commit does not match
-
-        @returns True: If all peer are updated to (or currently) in latest
-                       commit. False if any update fails
-
-        """
-        def _update_btpeer():
-            status = {}
-            for peer in self.host.btpeer_list:
-                status[peer] = {}
-                status[peer]['update_needed'] = \
-                    bluetooth_peer_update.is_update_needed(peer, commit)
-
-            logging.debug(status)
-            if not any([v['update_needed'] for v in status.values()]):
-                logging.info('No peer needed update')
-                return True
-            logging.debug('Atleast one peer needs update')
-
-            if not bluetooth_peer_update.download_installation_files(self.host,
-                                                                     commit):
-                logging.error('Unable to download installation files ')
-                return False
-
-            # TODO(b:160782273) Make this parallel
-            for peer in self.host.btpeer_list:
-                if status[peer]['update_needed']:
-                    status[peer]['updated'], status[peer]['reason'] = \
-                        bluetooth_peer_update.update_peer(peer, commit)
-
-            for peer, v in status.items():
-                if not v['update_needed']:
-                    logging.debug('peer %s did not need update', str(peer.host))
-                elif not v['updated']:
-                    logging.error('update peer %s failed %s', str(peer.host),
-                                  v['reason'])
-                else:
-                    logging.debug('peer %s updated successfully',
-                                  str(peer.host))
-
-            return all([v['updated'] for v in status.values()
-                        if v['update_needed']])
-
-        try:
-            build = self.host.get_release_version()
-            commit = bluetooth_peer_update.get_target_commit(
-                    self.host.hostname, build)
-            if commit is None:
-                logging.error('Unable to get current commit')
-                return False
-
-            return _update_btpeer()
-        except Exception as e:
-            logging.error('Exception %s in update_btpeer', str(e))
-            return False
-        finally:
-            if not bluetooth_peer_update.cleanup(self.host, commit):
-                logging.error('Update peer cleanup failed')
-
-
     def get_chipset_name(self):
         """ Get the name of BT/WiFi chipset on this host
 
diff --git a/server/cros/bluetooth/bluetooth_peer_update.py b/server/cros/bluetooth/bluetooth_peer_update.py
index d150876..57079c3 100644
--- a/server/cros/bluetooth/bluetooth_peer_update.py
+++ b/server/cros/bluetooth/bluetooth_peer_update.py
@@ -208,39 +208,69 @@
     return True, ''
 
 
-def update_peers(host, latest_commit):
-    """Update the chameleond on alll peer devices of an host"""
+def update_all_peers(host, raise_error=False):
+    """Update the chameleond on all peer devices of the given host
 
-    if host.btpeer_list == []:
-        raise error.TestError('Bluetooth Peer not present')
+    @param host: the DUT, usually a chromebook
+    @param raise_error: set this to True to raise an error if any
 
-    status = {}
-    for peer in host.btpeer_list:
-        #TODO(b:160782273) Make this parallel
-        status[peer] = {}
-        status[peer]['update_needed'] = is_update_needed(peer,latest_commit)
+    @returns: True if _update_all_peers success
+              False if raise_error=False and _update_all_peers failed
 
-    logging.debug(status)
-    if not any([v['update_needed'] for v in status.values()]):
-        logging.info("Update not needed on any of the peers")
-        return
-    for peer in host.btpeer_list:
-        if status[peer]['update_needed']:
-            status[peer]['updated'], status[peer]['reason'] = \
-            update_peer(peer, latest_commit)
+    @raises: error.TestFail if raise_error=True and _update_all_peers failed
+    """
+    fail_reason = _update_all_peers(host)
 
-    logging.debug(status)
-    # If any of the peers failed update, raise failure with the reason
-    if not all([v['updated'] for v in status.values() if v['update_needed']]):
-        for peer, v in status.items():
-            if v['update_needed']:
-                if not v['updated']:
-                    logging.error('updating peer %s failed %s', str(peer.host),
-                                  v['reason'])
-        raise error.TestFail()
+    if fail_reason:
+        if raise_error:
+            raise error.TestFail(fail_reason)
+        logging.error(fail_reason)
+        return False
+    else:
+        return True
 
-    logging.info('%s peers updated',len([v['updated'] for v in status.values()
-                                         if v['update_needed']]))
+
+def _update_all_peers(host):
+    """Update the chameleond on all peer devices of an host"""
+    try:
+        build = host.get_release_version()
+        target_commit = get_target_commit(host.hostname, build)
+        if target_commit is None:
+            return 'Unable to get current commit'
+
+        if host.btpeer_list == []:
+            return 'Bluetooth Peer not present'
+
+        peers_to_update = [
+                p for p in host.btpeer_list
+                if is_update_needed(p, target_commit)
+        ]
+
+        if not peers_to_update:
+            logging.info('No peer needed update')
+            return
+        logging.debug('At least one peer needs update')
+
+        if not download_installation_files(host, target_commit):
+            return 'Unable to download installation files'
+
+        # TODO(b:160782273) Make this parallel
+        failed_peers = []
+        for peer in peers_to_update:
+            updated, reason = update_peer(peer, target_commit)
+            if updated:
+                logging.info('peer %s updated successfully', str(peer.host))
+            else:
+                failed_peers.append((str(peer.host), reason))
+
+        if failed_peers:
+            return 'peer update failed (host, reason): %s' % failed_peers
+
+    except Exception as e:
+        return 'Exception raised in _update_all_peers: %s' % e
+    finally:
+        if not cleanup(host, target_commit):
+            return 'Update peer cleanup failed'
 
 
 def get_target_commit(hostname, host_build):
@@ -299,18 +329,6 @@
     return commit
 
 
-def get_latest_commit():
-    """Get the current chameleon bundle commit deployed in the lab.
-
-    This function exists for backward compatibility.
-    Remove this function once the bluetooth_PeerUpdate test is removed.
-
-    @returns the current commit in case of success; None in case of failure
-    """
-    commit = get_target_commit(hostname='', host_build='')
-    return bool(commit), commit
-
-
 def download_installation_files(host, commit):
     """ Download the chameleond installation bundle"""
     src_path = GS_PUBLIC + BUNDLE_TEMPLATE.format(commit)
diff --git a/server/site_tests/bluetooth_PeerUpdate/bluetooth_PeerUpdate.py b/server/site_tests/bluetooth_PeerUpdate/bluetooth_PeerUpdate.py
index 0b72d3f..83d2fee 100644
--- a/server/site_tests/bluetooth_PeerUpdate/bluetooth_PeerUpdate.py
+++ b/server/site_tests/bluetooth_PeerUpdate/bluetooth_PeerUpdate.py
@@ -12,7 +12,6 @@
 storage.
 """
 
-from autotest_lib.client.common_lib import error
 from autotest_lib.server import test
 from autotest_lib.server.cros.bluetooth import bluetooth_peer_update
 
@@ -29,17 +28,5 @@
 
         @param host: the DUT, usually a chromebook
         """
-        try:
-            self.host = host
-            self.host.initialize_btpeer(btpeer_args=btpeer_args)
-            commit = None
-            (_, commit) = bluetooth_peer_update.get_latest_commit()
-            if commit is None:
-                raise error.TestFail('Unable to get current commit')
-            if not bluetooth_peer_update.download_installation_files(self.host,
-                                                                     commit):
-                raise error.TestFail('Unable to download installation files ')
-            bluetooth_peer_update.update_peers(self.host, commit)
-        finally:
-            if not bluetooth_peer_update.cleanup(host, commit):
-                raise error.TestFail('Cleanup failed')
+        host.initialize_btpeer(btpeer_args=btpeer_args)
+        bluetooth_peer_update.update_all_peers(host, raise_error=True)