[Bluetooth] bt_AdapterPairing: add SR test

Adding suspend_resume control files to
bluetooth_AdapterPairing test.

BUG=chromium:724669
TEST=test_that ${DUT_IP}
bluetooth_AdapterPairing.mouse.suspend_resume
--args "chameleon_host=$CHAMELEON_IP"

Change-Id: I9002cbbf2a01caab0c983f85c78b731212021a96
Reviewed-on: https://chromium-review.googlesource.com/509936
Commit-Ready: Ruchi Jahagirdar <rjahagir@chromium.org>
Tested-by: Ruchi Jahagirdar <rjahagir@chromium.org>
Reviewed-by: Shyh-In Hwang <josephsih@chromium.org>
diff --git a/server/cros/bluetooth/bluetooth_adapter_tests.py b/server/cros/bluetooth/bluetooth_adapter_tests.py
index ded7481..4a46578 100644
--- a/server/cros/bluetooth/bluetooth_adapter_tests.py
+++ b/server/cros/bluetooth/bluetooth_adapter_tests.py
@@ -976,6 +976,83 @@
                 'disconnection_seen_by_adapter': disconnection_seen_by_adapter}
         return all(self.results.values())
 
+    @_test_retry_and_log
+    def test_device_is_connected(self, device_address):
+        """Test that device address given is currently connected.
+
+        @param device_address: Address of the device.
+
+        @returns: True if the device is connected.
+                  False otherwise.
+
+        """
+        def _is_connected():
+            """Test if device is connected.
+
+            @returns: True if device is connected. False otherwise.
+
+            """
+            return self.bluetooth_facade.device_is_connected(device_address)
+
+
+        method_name = 'test_device_is_connected'
+        has_device = False
+        connected = False
+        if self.bluetooth_facade.has_device(device_address):
+            has_device = True
+            try:
+                utils.poll_for_condition(
+                        condition=_is_connected,
+                        timeout=self.ADAPTER_CONNECTION_TIMEOUT_SECS,
+                        sleep_interval=self.ADAPTER_PAIRING_POLLING_SLEEP_SECS,
+                        desc='Waiting for connection to %s' % device_address)
+                connected = True
+            except utils.TimeoutError as e:
+                logging.error('%s: %s', method_name, e)
+            except:
+                logging.error('%s: unexpected error', method_name)
+        self.results = {'has_device': has_device, 'connected': connected}
+        return all(self.results.values())
+
+
+    @_test_retry_and_log
+    def test_device_is_paired(self, device_address):
+        """Test that the device address given is currently paired.
+
+        @param device_address: Address of the device.
+
+        @returns: True if the device is paired.
+                  False otherwise.
+
+        """
+        def _is_paired():
+            """Test if device is paired.
+
+            @returns: True if device is paired. False otherwise.
+
+            """
+            return self.bluetooth_facade.device_is_paired(device_address)
+
+
+        method_name = 'test_device_is_paired'
+        has_device = False
+        paired = False
+        if self.bluetooth_facade.has_device(device_address):
+            has_device = True
+            try:
+                utils.poll_for_condition(
+                        condition=_is_paired,
+                        timeout=self.ADAPTER_PAIRING_TIMEOUT_SECS,
+                        sleep_interval=self.ADAPTER_PAIRING_POLLING_SLEEP_SECS,
+                        desc='Waiting for connection to %s' % device_address)
+                paired = True
+            except utils.TimeoutError as e:
+                logging.error('%s: %s', method_name, e)
+            except:
+                logging.error('%s: unexpected error', method_name)
+        self.results = {'has_device': has_device, 'paired': paired}
+        return all(self.results.values())
+
 
     def _get_device_name(self, device_address):
         """Get the device name.
diff --git a/server/site_tests/bluetooth_AdapterPairing/bluetooth_AdapterPairing.py b/server/site_tests/bluetooth_AdapterPairing/bluetooth_AdapterPairing.py
index c172c38..5bf6bbf 100644
--- a/server/site_tests/bluetooth_AdapterPairing/bluetooth_AdapterPairing.py
+++ b/server/site_tests/bluetooth_AdapterPairing/bluetooth_AdapterPairing.py
@@ -2,7 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Server side bluetooth tests on adapter pairing and connecting to a bluetooth
+"""
+Server side bluetooth tests on adapter pairing and connecting to a bluetooth
 HID device.
 """
 
@@ -10,12 +11,12 @@
 import time
 
 from autotest_lib.client.common_lib import error
-from autotest_lib.server.cros.bluetooth.bluetooth_adapter_tests import (
-        BluetoothAdapterTests)
+from autotest_lib.server.cros.bluetooth import bluetooth_adapter_tests
 from autotest_lib.server.cros.multimedia import remote_facade_factory
 
 
-class bluetooth_AdapterPairing(BluetoothAdapterTests):
+class bluetooth_AdapterPairing(
+        bluetooth_adapter_tests.BluetoothAdapterTests):
     """Server side bluetooth adapter pairing and connecting to bluetooth device
 
     This test tries to verify that the adapter of the DUT could
@@ -32,8 +33,9 @@
     # TODO(josephsih): Reduce the sleep intervals to speed up the tests.
     TEST_SLEEP_SECS = 5
 
+
     def run_once(self, host, device_type, num_iterations=1, min_pass_count=1,
-                 pairing_twice=False):
+                 pairing_twice=False, suspend_resume=False, reboot=False):
         """Running Bluetooth adapter tests about pairing to a device.
 
         @param host: the DUT, usually a chromebook
@@ -42,11 +44,15 @@
         @param min_pass_count: the minimal pass count to pass this test
         @param pairing_twice: True if the host tries to pair the device
                 again after the paired device is removed.
+        @param suspend_resume: True if the host suspends/resumes after
+                pairing.
+        @param reboot: True if the host reboots after pairing.
 
         """
         self.host = host
         factory = remote_facade_factory.RemoteFacadeFactory(host)
         self.bluetooth_facade = factory.create_bluetooth_hid_facade()
+        self.input_facade = factory.create_input_facade()
 
         pass_count = 0
         self.total_fails = {}
@@ -95,6 +101,39 @@
             time.sleep(self.TEST_SLEEP_SECS)
             self.test_device_name(device.address, device.name)
 
+            # Test if the device is still connected after suspend/resume.
+            if suspend_resume:
+                self.suspend_resume()
+
+                time.sleep(self.TEST_SLEEP_SECS)
+                self.test_device_is_paired(device.address)
+
+                # After a suspend/resume, we need to wake the peripheral
+                # as it is not connected.
+                time.sleep(self.TEST_SLEEP_SECS)
+                self.test_connection_by_device(device.address)
+
+                time.sleep(self.TEST_SLEEP_SECS)
+                self.test_device_name(device.address, device.name)
+
+            # Test if the device is still connected after reboot.
+            # if reboot:
+            #     self.host.reboot()
+
+            #     time.sleep(self.TEST_SLEEP_SECS)
+            #     self.test_device_is_paired(device.address)
+
+            #     # After a reboot, we need to wake the peripheral
+            #     # as it is not connected.
+            #     time.sleep(self.TEST_SLEEP_SECS)
+            #     self.test_connection_by_adapter(device.address)
+
+            #     time.sleep(self.TEST_SLEEP_SECS)
+            #     self.test_device_is_connected(device.address)
+
+            #     time.sleep(self.TEST_SLEEP_SECS)
+            #     self.test_device_name(device.address, device.name)
+
             # Verify that the adapter could disconnect the device.
             self.test_disconnection_by_adapter(device.address)
 
diff --git a/server/site_tests/bluetooth_AdapterPairing/control.mouse.suspend_resume b/server/site_tests/bluetooth_AdapterPairing/control.mouse.suspend_resume
new file mode 100644
index 0000000..1459464
--- /dev/null
+++ b/server/site_tests/bluetooth_AdapterPairing/control.mouse.suspend_resume
@@ -0,0 +1,46 @@
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from autotest_lib.server import utils
+
+AUTHOR = 'rjahagir'
+NAME = 'bluetooth_AdapterPairing.mouse.suspend_resume'
+PURPOSE = 'Test adapter pairing and connecting to a bluetooth device after suspend/resume'
+CRITERIA = 'Adapter should work in correct states.'
+ATTRIBUTES = 'suite:bluetooth, suite:bluetooth_sanity'
+TIME = 'SHORT'    # This test takes about 2 minutes.
+TEST_CATEGORY = 'Functional'
+TEST_CLASS = 'bluetooth'
+TEST_TYPE = 'server'
+DEPENDENCIES = 'bluetooth, chameleon:bt_hid'
+
+DOC = """
+Verify that the bluetooth adapter of the DUT could pair and connect
+to a bluetooth device.
+
+Specifically, the following subtests are executed in this autotest.
+    - test_reset_on_adapter
+    - test_pairable
+    - test_discover_device
+    - test_stop_discovery
+    - test_device_name
+    - test_device_class_of_service
+    - test_device_class_of_device
+    - test_pairing
+    - test_connection_by_adapter
+    - test_disconnection_by_adapter
+    - test_connection_by_device
+    - test_disconnection_by_device
+    - test_remove_pairing
+"""
+
+args_dict = utils.args_to_dict(args)
+chameleon_args = hosts.CrosHost.get_chameleon_arguments(args_dict)
+
+def run(machine):
+    host = hosts.create_host(machine, chameleon_args=chameleon_args)
+    job.run_test('bluetooth_AdapterPairing', host=host, device_type='MOUSE',
+                 num_iterations=1, min_pass_count=1, suspend_resume=True)
+
+parallel_simple(run, machines)
\ No newline at end of file
diff --git a/server/site_tests/bluetooth_AdapterPairing/control.mouse.suspend_resume_stress_100 b/server/site_tests/bluetooth_AdapterPairing/control.mouse.suspend_resume_stress_100
new file mode 100644
index 0000000..051aa11
--- /dev/null
+++ b/server/site_tests/bluetooth_AdapterPairing/control.mouse.suspend_resume_stress_100
@@ -0,0 +1,47 @@
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from autotest_lib.server import utils
+
+AUTHOR = 'rjahagir'
+NAME = 'bluetooth_AdapterPairing.mouse.suspend_resume_stress_100'
+PURPOSE = ('Stress test for 100 iterations on bluetooth suspend/resume '
+           'and adapter pairing and connection.')
+CRITERIA = 'Adapter should work in correct states.'
+ATTRIBUTES = 'suite:bluetooth, suite:bluetooth_stress'
+TIME = 'LONG'   # This test takes about 3 hours.
+TEST_CATEGORY = 'Functional'
+TEST_CLASS = 'bluetooth'
+TEST_TYPE = 'server'
+DEPENDENCIES = 'bluetooth, chameleon:bt_hid'
+
+DOC = """
+Verify that the bluetooth adapter of the DUT could pair and connect
+to a bluetooth device.
+
+Specifically, the following subtests are executed in this autotest.
+    - test_reset_on_adapter
+    - test_pairable
+    - test_discover_device
+    - test_stop_discovery
+    - test_device_name
+    - test_device_class_of_service
+    - test_device_class_of_device
+    - test_pairing
+    - test_connection_by_adapter
+    - test_disconnection_by_adapter
+    - test_connection_by_device
+    - test_disconnection_by_device
+    - test_remove_pairing
+"""
+
+args_dict = utils.args_to_dict(args)
+chameleon_args = hosts.CrosHost.get_chameleon_arguments(args_dict)
+
+def run(machine):
+    host = hosts.create_host(machine, chameleon_args=chameleon_args)
+    job.run_test('bluetooth_AdapterPairing', host=host, device_type='MOUSE',
+                 num_iterations=100, min_pass_count=100, suspend_resume=True)
+
+parallel_simple(run, machines)
\ No newline at end of file