Adding volume change test for hotrod kiosk app.

Adding a test that changes the hangouts volume using hotrod kiosk app JS
hooks and validates the change against cras_test_client output.

BUG=chromium:614885
TEST=Locally

Change-Id: I720c92cbe8d31fcf372b7493af6aa31978892668
Reviewed-on: https://chromium-review.googlesource.com/349241
Commit-Ready: Harpreet Grewal <harpreet@chromium.org>
Tested-by: Harpreet Grewal <harpreet@chromium.org>
Reviewed-by: Harpreet Grewal <harpreet@chromium.org>
Reviewed-by: Kalin Stoyanov <kalin@chromium.org>
Reviewed-by: Jenny Zhang <jennyz@chromium.org>
diff --git a/client/common_lib/cros/cfm_util.py b/client/common_lib/cros/cfm_util.py
index 13ba968..d81b5f2 100644
--- a/client/common_lib/cros/cfm_util.py
+++ b/client/common_lib/cros/cfm_util.py
@@ -233,23 +233,40 @@
     logging.info('Mic is not muted.')
     return False
 
-
 def mute_mic(webview_context):
-    """Mute mic audio.
+    """Local mic mute from toolbar.
+
+    @param webview_context: Context for hangouts webview.
+    """
+    webview_context.ExecuteJavaScript("window.hrSetAudioInMutedForTest(true)")
+    logging.info('Locally muted mic.')
+
+
+def unmute_mic(webview_context):
+    """Local mic unmute from toolbar.
+
+    @param webview_context: Context for hangouts webview.
+    """
+    webview_context.ExecuteJavaScript("window.hrSetAudioInMutedForTest(false)")
+    logging.info('Locally unmuted mic.')
+
+
+def remote_mute_mic(webview_context):
+    """Remote mic mute request from cPanel.
 
     @param webview_context: Context for hangouts webview.
     """
     webview_context.ExecuteJavaScript("window.hrMuteAudioForTest()")
-    logging.info('Mute audio.')
+    logging.info('Remotely muted mic.')
 
 
-def unmute_mic(webview_context):
-    """Unmute mic audio.
+def remote_unmute_mic(webview_context):
+    """Remote mic unmute request from cPanel.
 
     @param webview_context: Context for hangouts webview.
     """
     webview_context.ExecuteJavaScript("window.hrUnmuteAudioForTest()")
-    logging.info('Unmute audio.')
+    logging.info('Remotely unmuted mic.')
 
 
 def get_mic_devices(webview_context):
@@ -315,11 +332,11 @@
     """Set speaker volume.
 
     @param webview_context: Context for hangouts webview.
-    @param volume_level: Integer value ranging from 0-100 to set volume to.
+    @param volume_level: String value ranging from 0-100 to set volume to.
     """
     webview_context.ExecuteJavaScript(
             "window.hrSetAudioOutVolumeLevelForTest(" + volume_level + ")")
-    logging.info('Set speaker volume to %d', volume_level)
+    logging.info('Set speaker volume to %s', volume_level)
 
 
 def get_speaker_volume(webview_context):
diff --git a/client/site_tests/enterprise_CFM_VolumeChangeClient/enterprise_CFM_VolumeChangeClient.py b/client/site_tests/enterprise_CFM_VolumeChangeClient/enterprise_CFM_VolumeChangeClient.py
new file mode 100644
index 0000000..99f468b
--- /dev/null
+++ b/client/site_tests/enterprise_CFM_VolumeChangeClient/enterprise_CFM_VolumeChangeClient.py
@@ -0,0 +1,103 @@
+# Copyright 2016 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.
+
+import datetime, logging, random, time
+
+from autotest_lib.client.bin import test
+from autotest_lib.client.common_lib import error, utils
+from autotest_lib.client.common_lib.cros import chrome, cfm_util
+
+LONG_TIMEOUT = 10
+SHORT_TIMEOUT = 2
+EXT_ID = 'ikfcpmgefdpheiiomgmhlmmkihchmdlj'
+CMD = "cras_test_client --dump_server_info | awk '/Output Nodes:/," \
+      "/Input Devices:/' | grep -E 'USB' | awk -v N=3 '{print $N}'"
+
+
+class enterprise_CFM_VolumeChangeClient(test.test):
+    """Volume changes made in the CFM / hotrod app should be accurately
+    reflected in CrOS.
+    """
+    version = 1
+
+
+    def _start_hangout_session(self, webview_context):
+        """Start a hangout session.
+
+        @param webview_context: Context for hangouts webview.
+        @raises error.TestFail if any of the checks fail.
+        """
+        current_time = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
+        hangout_name = 'auto-hangout-' + current_time
+        logging.info('Session name: %s', hangout_name)
+
+        if not cfm_util.is_ready_to_start_hangout_session(webview_context):
+            raise error.TestFail('CFM should be ready to start new session.')
+
+        cfm_util.start_new_hangout_session(webview_context, hangout_name)
+
+        if not cfm_util.is_in_hangout_session(webview_context):
+            raise error.TestFail('CFM was not able to start hangout session.')
+
+        if cfm_util.is_ready_to_start_hangout_session(webview_context):
+            raise error.TestFail('Is already in hangout session and should not '
+                                 'be able to start another session.')
+
+        time.sleep(SHORT_TIMEOUT)
+
+        if cfm_util.is_mic_muted(webview_context):
+            cfm_util.unmute_mic(webview_context)
+
+
+    def _end_hangout_session(self, webview_context):
+        """End hangout session.
+
+        @param webview_context: Context for hangouts window.
+        """
+        cfm_util.end_hangout_session(webview_context)
+
+        if cfm_util.is_in_hangout_session(webview_context):
+            raise error.TestFail('CFM should not be in hangout session.')
+
+
+    def run_once(self, repeat):
+        """Runs the test."""
+        with chrome.Chrome(clear_enterprise_policy=False,
+                           dont_override_profile=True,
+                           disable_gaia_services=False,
+                           disable_default_apps=False,
+                           auto_login=False) as cr:
+            cfm_webview_context = cfm_util.get_cfm_webview_context(
+                    cr.browser, EXT_ID)
+
+            cfm_util.wait_for_telemetry_commands(cfm_webview_context)
+            cfm_util.wait_for_oobe_start_page(cfm_webview_context)
+
+            if not cfm_util.is_oobe_start_page(cfm_webview_context):
+                raise error.TestFail('CFM did not reach oobe screen.')
+
+            cfm_util.skip_oobe_screen(cfm_webview_context)
+            self._start_hangout_session(cfm_webview_context)
+
+            # This is used to trigger crbug.com/614885
+            for volume in range(55, 85):
+                cfm_util.set_speaker_volume(cfm_webview_context, str(volume))
+                time.sleep(random.uniform(0.01, 0.05))
+
+            while repeat:
+                cfm_volume = str(random.randrange(0, 100, 1))
+                cfm_util.set_speaker_volume(cfm_webview_context, cfm_volume)
+                time.sleep(SHORT_TIMEOUT)
+
+                cras_volume = utils.system_output(CMD)
+                if cras_volume != cfm_volume:
+                    raise error.TestFail('Cras volume (%s) does not match '
+                                         'volume set by CFM (%s).' %
+                                         (cras_volume, cfm_volume))
+                logging.info('Cras volume (%s) matches volume set by CFM (%s)',
+                             cras_volume, cfm_volume)
+
+                repeat -= 1
+
+            self._end_hangout_session(cfm_webview_context)
diff --git a/server/site_tests/enterprise_CFM_VolumeChange/control b/server/site_tests/enterprise_CFM_VolumeChange/control
new file mode 100644
index 0000000..37ca625
--- /dev/null
+++ b/server/site_tests/enterprise_CFM_VolumeChange/control
@@ -0,0 +1,35 @@
+# Copyright 2016 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 = "harpreet@chromium.org"
+NAME = "enterprise_CFM_VolumeChange"
+TIME = "SHORT"
+TEST_CATEGORY = "Functional"
+TEST_CLASS = "enterprise"
+TEST_TYPE = "server"
+ATTRIBUTES = "suite:hotrod"
+
+DOC = """
+This test clears the TPM and enables the appropriate usb port on the servo
+before kicking off a client side test that enrolls the device into CFM. Once
+the device in enrolled, a different client test is kicked off to change the
+hangouts volume using hotrod kiosk app JS hooks. These changes are then
+validated against the cras_test_client output to make sure the volume matches.
+"""
+
+args_dict = utils.args_to_dict(args)
+servo_args = hosts.CrosHost.get_servo_arguments(args_dict)
+
+def run_test(machine):
+    host = hosts.create_host(machine, servo_args=servo_args)
+    repeat = int(args_dict.get('repeat', 10))
+
+    job.run_test('enterprise_CFM_VolumeChange',
+                 host=host,
+                 repeat=repeat)
+
+
+parallel_simple(run_test, machines)
diff --git a/server/site_tests/enterprise_CFM_VolumeChange/enterprise_CFM_VolumeChange.py b/server/site_tests/enterprise_CFM_VolumeChange/enterprise_CFM_VolumeChange.py
new file mode 100644
index 0000000..1d8eca7
--- /dev/null
+++ b/server/site_tests/enterprise_CFM_VolumeChange/enterprise_CFM_VolumeChange.py
@@ -0,0 +1,31 @@
+# Copyright 2016 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.client.common_lib.cros import tpm_utils
+from autotest_lib.server import test, autotest
+
+
+class enterprise_CFM_VolumeChange(test.test):
+    """Validate volume changes made in hotrod kiosk app against CrOS.
+    """
+    version = 1
+
+    def run_once(self, host, repeat):
+        self.client = host
+
+        tpm_utils.ClearTPMOwnerRequest(self.client)
+
+        if self.client.servo:
+            self.client.servo.switch_usbkey('dut')
+            self.client.servo.set('usb_mux_sel3', 'dut_sees_usbkey')
+            self.client.servo.set('dut_hub1_rst1', 'off')
+
+        autotest.Autotest(self.client).run_test(
+                'enterprise_RemoraRequisition', check_client_result=True)
+        autotest.Autotest(self.client).run_test(
+                'enterprise_CFM_VolumeChangeClient',
+                repeat=repeat,
+                check_client_result=True)
+
+        tpm_utils.ClearTPMOwnerRequest(self.client)