1# Copyright 2017 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import logging 6import os 7import time 8 9from autotest_lib.server import test 10from autotest_lib.client.common_lib import error 11from autotest_lib.client.common_lib.cros import tpm_utils 12from autotest_lib.server.cros.multimedia import remote_facade_factory 13 14SHORT_TIMEOUT = 5 15 16 17class CfmBaseTest(test.test): 18 """ 19 Base class for Cfm enterprise tests. 20 21 CfmBaseTest provides common setup and cleanup methods. This base class is 22 agnostic with respect to 'hangouts classic' vs. 'hangouts meet' - it works 23 for both flavors. 24 """ 25 26 def initialize(self, host, run_test_only=False, skip_enrollment=False): 27 """ 28 Initializes common test properties. 29 30 @param host: a host object representing the DUT. 31 @param run_test_only: Wheter to run only the test or to also perform 32 deprovisioning, enrollment and system reboot. If set to 'True', 33 the DUT must already be enrolled and past the OOB screen to be able 34 to execute the test. 35 @param skip_enrollment: Whether to skip the enrollment step. Cleanup 36 at the end of the test is done regardless. 37 """ 38 super(CfmBaseTest, self).initialize() 39 self._host = host 40 self._run_test_only = run_test_only 41 self._skip_enrollment = skip_enrollment 42 self._facade_factory = remote_facade_factory.RemoteFacadeFactory( 43 self._host, no_chrome = True) 44 self.cfm_facade = self._facade_factory.create_cfm_facade() 45 46 def setup(self): 47 """ 48 Performs common test setup operations: 49 - clears the TPM 50 - sets up servo 51 - enrolls the device 52 - skips OOBE 53 """ 54 super(CfmBaseTest, self).setup() 55 if self._host.servo: 56 self._setup_servo() 57 58 if self._run_test_only or self._skip_enrollment: 59 # We need to restart the browser to obtain the handle for it when 60 # running in test_only mode. 61 self.cfm_facade.restart_chrome_for_cfm() 62 else: 63 logging.info('Clearing TPM & rebooting afterwards...') 64 tpm_utils.ClearTPMOwnerRequest(self._host) 65 logging.info('Enrolling device') 66 self.cfm_facade.enroll_device() 67 logging.info('Skipping OOBE') 68 self.cfm_facade.skip_oobe_after_enrollment() 69 70 def _setup_servo(self): 71 """ 72 Enables the USB port such that any peripheral connected to it is visible 73 to the DUT. 74 """ 75 try: 76 # Servos have a USB key connected for recovery. The following code 77 # sets up the servo so that the DUT (and not the servo) sees this 78 # USB key as a device. 79 # We do not generally need this in tests, why we ignore any 80 # errors here. This also seems to fail on Servo V4 but we 81 # don't need it in any tests with that setup. 82 self._host.servo.switch_usbkey('dut') 83 self._host.servo.set('usb_mux_sel3', 'dut_sees_usbkey') 84 time.sleep(SHORT_TIMEOUT) 85 self._host.servo.set('dut_hub1_rst1', 'off') 86 time.sleep(SHORT_TIMEOUT) 87 except error.TestFail: 88 logging.warn('Failed to configure servo. This is not fatal unless ' 89 'your test is explicitly using the servo.', 90 exc_info=True) 91 92 def cleanup(self, run_test_only=False): 93 """Takes a screenshot, saves log files and clears the TPM.""" 94 self.take_screenshot('%s' % self.tagged_testname) 95 self.save_callgrok_logs() 96 self.save_packaged_app_logs() 97 if not self._run_test_only: 98 logging.info('[CLEAN UP] Clearing TPM (without reboot)...') 99 self._only_clear_tpm() 100 super(CfmBaseTest, self).cleanup() 101 102 def _only_clear_tpm(self): 103 if not self._host.run('crossystem clear_tpm_owner_request=1', 104 ignore_status=True).exit_status == 0: 105 raise error.TestFail('Unable to clear TPM.') 106 107 def take_screenshot(self, screenshot_name): 108 """ 109 Takes a screenshot (in .png format) and saves it in the debug dir. 110 111 @param screenshot_name: Name of the screenshot file without extension. 112 """ 113 try: 114 target_dir = self.debugdir 115 logging.info('Taking screenshot and saving under %s...', 116 target_dir) 117 remote_path = self.cfm_facade.take_screenshot() 118 if remote_path: 119 # Copy the screenshot from the DUT. 120 self._safe_copy_file( 121 remote_path, 122 os.path.join(target_dir, screenshot_name + '.png')) 123 else: 124 logging.warning('Taking screenshot failed') 125 except Exception as e: 126 logging.exception('Exception while taking a screenshot.') 127 128 def save_callgrok_logs(self): 129 """ 130 Copies the callgrok logs from the client to test's debug directory. 131 """ 132 callgrok_log_path = self.cfm_facade.get_latest_callgrok_file_path() 133 if callgrok_log_path: 134 self._safe_copy_file( 135 callgrok_log_path, 136 os.path.join(self.debugdir, 'callgrok_logs.txt')) 137 else: 138 logging.warning('No callgrok logs found on DUT.') 139 140 def save_packaged_app_logs(self): 141 """ 142 Copies the packaged app logs from the client to test's debug directory. 143 """ 144 pa_log_path = self.cfm_facade.get_latest_pa_logs_file_path() 145 if pa_log_path: 146 self._safe_copy_file( 147 pa_log_path, 148 os.path.join(self.debugdir, 'packaged_app_logs.txt')) 149 else: 150 logging.warning('No packaged app logs found on DUT.') 151 152 def save_all_packaged_app_logs(self): 153 """ 154 Copies the packaged app logs from the client to test's debug directory. 155 """ 156 pa_log_paths = self.cfm_facade.get_all_pa_logs_file_path() 157 if not pa_log_paths: 158 logging.warning('No packaged app logs found on DUT.') 159 return 160 for log_file in pa_log_paths: 161 log_filename = ( 162 'packaged_app_log_%s.txt' % os.path.basename(log_file)) 163 self._safe_copy_file( 164 log_file, os.path.join(self.debugdir, log_filename)) 165 166 def _safe_copy_file(self, remote_path, local_path): 167 """ 168 Copies the packaged app log file from CFM to test's debug directory. 169 """ 170 try: 171 logging.info('Copying file "%s" from client to "%s"...', 172 remote_path, local_path) 173 self._host.get_file(remote_path, local_path) 174 except Exception as e: 175 logging.exception( 176 'Exception while copying file "%s"', remote_path) 177 178