Adding CFM sanity test and doing some refactoring.
Add CFM sanity test utilizing hangout JS commands to test basic hangouts
functionality like starting a hangout, muting/unmuting mic, exiting
hangout, detecting peripherals and running hotrod diagnostics.
BUG=chromium:597138
TEST=Tested on a local setup with test_that
Change-Id: Ic315f38f1d0f6ecca55a30973cfa9665bbc96bb2
Reviewed-on: https://chromium-review.googlesource.com/334259
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>
diff --git a/client/common_lib/cros/cfm_util.py b/client/common_lib/cros/cfm_util.py
new file mode 100644
index 0000000..dbf7b1c
--- /dev/null
+++ b/client/common_lib/cros/cfm_util.py
@@ -0,0 +1,290 @@
+# 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 logging
+
+from autotest_lib.client.bin import utils
+from autotest_lib.client.common_lib import error
+from autotest_lib.client.common_lib.cros import chrome
+
+DEFAULT_TIMEOUT = 30
+DIAGNOSTIC_RUN_TIMEOUT = 180
+
+def get_cfm_webview_context(browser, ext_id):
+ """Get context for CFM webview.
+
+ @param broswer: Telemetry broswer object.
+ @param ext_id: Extension id of the hangouts app.
+ @return webview context.
+ """
+ ext_contexts = wait_for_hangouts_ext(browser, ext_id)
+
+ for context in ext_contexts:
+ context.WaitForDocumentReadyStateToBeInteractiveOrBetter()
+ tagName = context.EvaluateJavaScript(
+ "document.querySelector('webview') ? 'WEBVIEW' : 'NOWEBVIEW'")
+
+ if tagName == "WEBVIEW":
+ def webview_context():
+ try:
+ wb_contexts = context.GetWebviewContexts()
+ if len(wb_contexts) == 1:
+ return wb_contexts[0]
+ except (KeyError, chrome.Error):
+ pass
+ return None
+ return utils.poll_for_condition(
+ webview_context,
+ exception=error.TestFail('Hangouts webview not available.'),
+ timeout=DEFAULT_TIMEOUT,
+ sleep_interval=1)
+
+
+def wait_for_hangouts_ext(browser, ext_id):
+ """Wait for hangouts extension launch.
+
+ @param browser: Telemetry browser object.
+ @param ext_id: Extension id of the hangouts app.
+ @return extension contexts.
+ """
+ def hangout_ext_contexts():
+ try:
+ ext_contexts = browser.extensions.GetByExtensionId(ext_id)
+ if len(ext_contexts) > 1:
+ return ext_contexts
+ except (KeyError, chrome.Error):
+ pass
+ return []
+ return utils.poll_for_condition(
+ hangout_ext_contexts,
+ exception=error.TestFail('Hangouts app failed to launch'),
+ timeout=DEFAULT_TIMEOUT,
+ sleep_interval=1)
+
+
+def wait_for_telemetry_commands(webview_context):
+ """Wait for hotrod app to load and telemetry commands to be available.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ webview_context.WaitForJavaScriptExpression(
+ "typeof window.hrOobIsStartPageForTest == 'function'",
+ DEFAULT_TIMEOUT)
+ logging.info('Hotrod telemetry commands available for testing.')
+
+
+def wait_for_oobe_start_page(webview_context):
+ """Wait for oobe start screen to launch.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ webview_context.WaitForJavaScriptExpression(
+ "window.hrOobIsStartPageForTest() === true;", DEFAULT_TIMEOUT)
+ logging.info('Reached oobe start page')
+
+
+def skip_oobe_screen(webview_context):
+ """Skip Chromebox for Meetings oobe screen.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ webview_context.ExecuteJavaScript("window.hrOobSkipForTest()")
+ utils.poll_for_condition(lambda: not webview_context.EvaluateJavaScript(
+ "window.hrOobIsStartPageForTest()"),
+ exception=error.TestFail('Not able to skip oobe screen.'),
+ timeout=DEFAULT_TIMEOUT,
+ sleep_interval=1)
+ logging.info('Skipped oobe screen.')
+
+
+def start_new_hangout_session(webview_context, hangout_name):
+ """Start a new hangout session.
+
+ @param webview_context: Context for hangouts webview.
+ @param hangout_name: Name of the hangout session.
+ """
+ if not is_ready_to_start_hangout_session(webview_context):
+ if is_in_hangout_session(webview_context):
+ end_hangout_session(webview_context)
+
+ webview_context.ExecuteJavaScript("window.hrStartCallForTest('" +
+ hangout_name + "')")
+ utils.poll_for_condition(lambda: webview_context.EvaluateJavaScript(
+ "window.hrIsInHangoutForTest()"),
+ exception=error.TestFail('Not able to start session.'),
+ timeout=DEFAULT_TIMEOUT,
+ sleep_interval=1)
+ logging.info('Started hangout session: %s', hangout_name)
+
+
+def end_hangout_session(webview_context):
+ """End current hangout session.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ webview_context.ExecuteJavaScript("window.hrHangupCallForTest()")
+ utils.poll_for_condition(lambda: not webview_context.EvaluateJavaScript(
+ "window.hrIsInHangoutForTest()"),
+ exception=error.TestFail('Not able to end session.'),
+ timeout=DEFAULT_TIMEOUT,
+ sleep_interval=1)
+
+ logging.info('Ended hangout session.')
+
+
+def mute_audio(webview_context):
+ """Mute mic audio.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ webview_context.ExecuteJavaScript("window.hrMuteAudioForTest()")
+ logging.info('Mute audio.')
+
+
+def unmute_audio(webview_context):
+ """Unmute mic audio.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ webview_context.ExecuteJavaScript("window.hrUnmuteAudioForTest()")
+ logging.info('Unmute audio.')
+
+
+def is_oobe_start_page(webview_context):
+ """Check if device is on CFM oobe start screen.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ if webview_context.EvaluateJavaScript("window.hrOobIsStartPageForTest()"):
+ logging.info('Is on oobe start page.')
+ return True
+ logging.info('Is not on oobe start page.')
+ return False
+
+
+def is_in_hangout_session(webview_context):
+ """Check if device is in hangout session.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ if webview_context.EvaluateJavaScript("window.hrIsInHangoutForTest()"):
+ logging.info('Is in hangout session.')
+ return True
+ logging.info('Is not in hangout session.')
+ return False
+
+
+def is_ready_to_start_hangout_session(webview_context):
+ """Check if device is ready to start a new hangout session.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ if (webview_context.EvaluateJavaScript(
+ "window.hrIsReadyToStartHangoutForTest()")):
+ logging.info('Is ready to start hangout session.')
+ return True
+ logging.info('Is not ready to start hangout session.')
+ return False
+
+
+def is_diagnostic_run_in_progress(webview_context):
+ """Check if hotrod diagnostics is running.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ if (webview_context.EvaluateJavaScript(
+ "window.hrIsDiagnosticRunInProgressForTest()")):
+ logging.info('Diagnostic run is in progress.')
+ return True
+ logging.info('Diagnostic run is not in progress.')
+ return False
+
+
+def wait_for_diagnostic_run_to_complete(webview_context):
+ """Wait for hotrod diagnostics to complete.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ utils.poll_for_condition(lambda: not webview_context.EvaluateJavaScript(
+ "window.hrIsDiagnosticRunInProgressForTest()"),
+ exception=error.TestError('Diagnostic run still in progress after '
+ '3 minutes.'),
+ timeout=DIAGNOSTIC_RUN_TIMEOUT,
+ sleep_interval=1)
+
+
+def run_diagnostics(webview_context):
+ """Run hotrod diagnostics.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ if is_diagnostic_run_in_progress(webview_context):
+ wait_for_diagnostic_run_to_complete(webview_context)
+ webview_context.ExecuteJavaScript("window.hrRunDiagnosticsForTest()")
+ logging.info('Started diagnostics run.')
+
+
+def get_last_diagnostics_results(webview_context):
+ """Get latest hotrod diagnostics results.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ if is_diagnostic_run_in_progress(webview_context):
+ wait_for_diagnostic_run_to_complete(webview_context)
+ return webview_context.EvaluateJavaScript(
+ "window.hrGetLastDiagnosticsResultForTest()")
+
+
+def get_mic_devices(webview_context):
+ """Get all mic devices detected by hotrod.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ return webview_context.EvaluateJavaScript(
+ "window.hrGetAudioInDevicesForTest()")
+
+
+def get_speaker_devices(webview_context):
+ """Get all speaker devices detected by hotrod.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ return webview_context.EvaluateJavaScript(
+ "window.hrGetAudioOutDevicesForTest()")
+
+
+def get_camera_devices(webview_context):
+ """Get all camera devices detected by hotrod.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ return webview_context.EvaluateJavaScript(
+ "window.hrGetVideoCaptureDevicesForTest()")
+
+
+def get_preferred_mic(webview_context):
+ """Get mic preferred for hotrod.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ return webview_context.EvaluateJavaScript(
+ "window.hrGetAudioInPrefForTest()")
+
+
+def get_preferred_speaker(webview_context):
+ """Get speaker preferred for hotrod.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ return webview_context.EvaluateJavaScript(
+ "window.hrGetAudioOutPrefForTest()")
+
+
+def get_preferred_camera(webview_context):
+ """Get camera preferred for hotrod.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ return webview_context.EvaluateJavaScript(
+ "window.hrGetVideoCapturePrefForTest()")
diff --git a/client/site_tests/enterprise_CFM_Sanity/control b/client/site_tests/enterprise_CFM_Sanity/control
new file mode 100644
index 0000000..cf4dc3a
--- /dev/null
+++ b/client/site_tests/enterprise_CFM_Sanity/control
@@ -0,0 +1,17 @@
+# 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.
+
+AUTHOR = "harpreet@chromium.org"
+NAME = "enterprise_CFM_Sanity"
+TIME = "SHORT"
+TEST_CATEGORY = "Enterprise"
+TEST_CLASS = "enterprise"
+TEST_TYPE = "client"
+
+DOC = """
+This test runs a series of test actions and performs verifications to make sure
+CFM enrolled devices behave as expected.
+"""
+
+job.run_test('enterprise_CFM_Sanity')
diff --git a/client/site_tests/enterprise_CFM_Sanity/enterprise_CFM_Sanity.py b/client/site_tests/enterprise_CFM_Sanity/enterprise_CFM_Sanity.py
new file mode 100644
index 0000000..263dedd
--- /dev/null
+++ b/client/site_tests/enterprise_CFM_Sanity/enterprise_CFM_Sanity.py
@@ -0,0 +1,148 @@
+# 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, time
+
+from autotest_lib.client.bin import test
+from autotest_lib.client.common_lib import error
+from autotest_lib.client.common_lib.cros import chrome, cfm_util
+
+LONG_TIMEOUT = 10
+SHORT_TIMEOUT = 2
+EXT_ID = 'ikfcpmgefdpheiiomgmhlmmkihchmdlj'
+FAILED_TEST_LIST = list()
+
+
+class enterprise_CFM_Sanity(test.test):
+ """Tests the following fuctionality works on CFM enrolled devices:
+ 1. Is able to reach the oobe screen
+ 2. Is able to start a hangout session
+ 3. Should not be able to start a hangout session if already in a
+ session.
+ 4. Exits hangout session successfully.
+ 5. Should be able to start a hangout session if currently not in
+ a session.
+ 6. Is able to detect attached peripherals: mic, speaker, camera.
+ 7. Is able to run hotrod diagnostics.
+ """
+ version = 1
+
+
+ def _hangouts_sanity_test(self, webview_context):
+ """Execute a series of test actions and perform verifications.
+
+ @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
+
+ cfm_util.wait_for_telemetry_commands(webview_context)
+ cfm_util.wait_for_oobe_start_page(webview_context)
+
+ if not cfm_util.is_oobe_start_page(webview_context):
+ raise error.TestFail('CFM did not reach oobe screen.')
+
+ cfm_util.skip_oobe_screen(webview_context)
+
+ if cfm_util.is_ready_to_start_hangout_session(webview_context):
+ 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.')
+
+ time.sleep(LONG_TIMEOUT)
+ cfm_util.unmute_audio(webview_context)
+
+ 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.')
+
+ if cfm_util.is_oobe_start_page(webview_context):
+ raise error.TestFail('CFM should be in hangout session and not on '
+ 'oobe screen.')
+
+ time.sleep(SHORT_TIMEOUT)
+ cfm_util.mute_audio(webview_context)
+ time.sleep(SHORT_TIMEOUT)
+ 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.')
+
+ if cfm_util.is_oobe_start_page(webview_context):
+ raise error.TestFail('CFM should not be on oobe screen.')
+
+ if not cfm_util.is_ready_to_start_hangout_session(webview_context):
+ raise error.TestFail('CFM should be in read state to start hangout '
+ 'session.')
+
+
+ def _peripherals_sanity_test(self, webview_context):
+ """Checks for connected peripherals.
+
+ @param webview_context: Context for hangouts webview.
+ """
+ cfm_util.wait_for_telemetry_commands(webview_context)
+
+ time.sleep(SHORT_TIMEOUT)
+
+ if not cfm_util.get_mic_devices(webview_context):
+ FAILED_TEST_LIST.append('No mic detected')
+
+ if not cfm_util.get_speaker_devices(webview_context):
+ FAILED_TEST_LIST.append('No speaker detected')
+
+ if not cfm_util.get_camera_devices(webview_context):
+ FAILED_TEST_LIST.append('No camera detected')
+
+ if not cfm_util.get_preferred_mic(webview_context):
+ FAILED_TEST_LIST.append('No preferred mic')
+
+ if not cfm_util.get_preferred_speaker(webview_context):
+ FAILED_TEST_LIST.append('No preferred speaker')
+
+ if not cfm_util.get_preferred_camera(webview_context):
+ FAILED_TEST_LIST.append('No preferred camera')
+
+
+ def _diagnostics_sanity_test(self, webview_context):
+ """Runs hotrod diagnostics and checks status.
+
+ @param webview_context: Context for hangouts webview.
+ @raise error.TestFail if diagnostic checks fail.
+ """
+ cfm_util.wait_for_telemetry_commands(webview_context)
+
+ if cfm_util.is_diagnostic_run_in_progress(webview_context):
+ raise error.TestFail('Diagnostics should not be running.')
+
+ cfm_util.run_diagnostics(webview_context)
+
+ if not cfm_util.is_diagnostic_run_in_progress(webview_context):
+ raise error.TestFail('Diagnostics should be running.')
+
+ diag_results = cfm_util.get_last_diagnostics_results(webview_context)
+
+ if diag_results['status'] not in 'success':
+ logging.debug(diag_results['childrens'])
+ FAILED_TEST_LIST.append('Diagnostics failed')
+
+
+ def run_once(self):
+ """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)
+ self._hangouts_sanity_test(cfm_webview_context)
+ self._peripherals_sanity_test(cfm_webview_context)
+ self._diagnostics_sanity_test(cfm_webview_context)
+
+ if FAILED_TEST_LIST:
+ raise error.TestFail('Test failed because of following reasons: %s'
+ % ', '.join(map(str, FAILED_TEST_LIST)))
diff --git a/client/site_tests/enterprise_RemoraRequisition/credentials.txt b/client/site_tests/enterprise_RemoraRequisition/credentials.txt
index f6157e1..a8e8614 100644
--- a/client/site_tests/enterprise_RemoraRequisition/credentials.txt
+++ b/client/site_tests/enterprise_RemoraRequisition/credentials.txt
@@ -1 +1 @@
-hotrodmtv@remora-test.mygbiz.com:test0000
+cfmtest@croste.tv:test0000
diff --git a/client/site_tests/enterprise_RemoraRequisition/enterprise_RemoraRequisition.py b/client/site_tests/enterprise_RemoraRequisition/enterprise_RemoraRequisition.py
index ee4ee2e..1999c3f 100644
--- a/client/site_tests/enterprise_RemoraRequisition/enterprise_RemoraRequisition.py
+++ b/client/site_tests/enterprise_RemoraRequisition/enterprise_RemoraRequisition.py
@@ -6,7 +6,7 @@
from autotest_lib.client.bin import test, utils
from autotest_lib.client.common_lib import error
-from autotest_lib.client.common_lib.cros import chrome, enrollment
+from autotest_lib.client.common_lib.cros import chrome, enrollment, cfm_util
TIMEOUT = 20
@@ -14,26 +14,11 @@
"""Enroll as a Remora device."""
version = 1
- _HANGOUTS_EXT_ID = 'acdafoiapclbpdkhnighhilgampkglpc'
-
- def _WaitForHangouts(self, browser):
- def _HangoutExtContexts():
- try:
- ext_contexts = browser.extensions.GetByExtensionId(
- self._HANGOUTS_EXT_ID)
- if len(ext_contexts) > 1:
- return ext_contexts
- except (KeyError, chrome.Error):
- pass
- return []
- return utils.poll_for_condition(
- _HangoutExtContexts,
- exception=error.TestFail('Hangouts app failed to launch'),
- timeout=30,
- sleep_interval=1)
+ _HANGOUTS_EXT_ID = 'ikfcpmgefdpheiiomgmhlmmkihchmdlj'
def _CheckHangoutsExtensionContexts(self, browser):
- ext_contexts = self._WaitForHangouts(browser)
+ ext_contexts = cfm_util.wait_for_hangouts_ext(
+ browser, self._HANGOUTS_EXT_ID)
ext_urls = set([context.EvaluateJavaScript('location.href;')
for context in ext_contexts])
expected_urls = set(
diff --git a/server/site_tests/enterprise_CFM_SanityServer/control b/server/site_tests/enterprise_CFM_SanityServer/control
new file mode 100644
index 0000000..522f72a
--- /dev/null
+++ b/server/site_tests/enterprise_CFM_SanityServer/control
@@ -0,0 +1,25 @@
+# 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.
+
+AUTHOR = "harpreet@chromium.org"
+NAME = "enterprise_CFM_SanityServer"
+TIME = "SHORT"
+TEST_CATEGORY = "Functional"
+TEST_CLASS = "enterprise"
+TEST_TYPE = "server"
+ATTRIBUTES = "suite:hotrod"
+
+DOC = """
+This test clears the TPM if necessary, kicks off a client side test that enrolls
+a device as a remora device and runs a client sanity test followed by clearing
+the TPM again. Every time the TPM is cleared, the system is rebooted.
+"""
+
+
+def run_test(machine):
+ host = hosts.create_host(machine)
+ job.run_test('enterprise_CFM_SanityServer', host=host)
+
+
+parallel_simple(run_test, machines)
diff --git a/server/site_tests/enterprise_CFM_SanityServer/enterprise_CFM_SanityServer.py b/server/site_tests/enterprise_CFM_SanityServer/enterprise_CFM_SanityServer.py
new file mode 100644
index 0000000..3a3802c
--- /dev/null
+++ b/server/site_tests/enterprise_CFM_SanityServer/enterprise_CFM_SanityServer.py
@@ -0,0 +1,21 @@
+# 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_SanityServer(test.test):
+ """A test that clears the TPM and runs enterprise_RemoraRequisition to
+ enroll the device into Chromebox for Meetings. After successful enrollment,
+ it runs the CFM sanity test."""
+ version = 1
+
+ def run_once(self, host=None):
+ self.client = host
+
+ tpm_utils.ClearTPMOwnerRequest(self.client)
+ autotest.Autotest(self.client).run_test('enterprise_RemoraRequisition')
+ autotest.Autotest(self.client).run_test('enterprise_CFM_Sanity')
+ tpm_utils.ClearTPMOwnerRequest(self.client)