# Lint as: python2, python3 # Copyright 2018 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 contextlib import json import logging import os import time from autotest_lib.client.common_lib import error, utils class ChartFixture: """Sets up chart tablet to display placeholder scene image.""" DISPLAY_SCRIPT = '/usr/local/autotest/bin/display_chart.py' OUTPUT_LOG = '/tmp/chart_service.log' def __init__(self, chart_host, scene_uri, job=None): self.host = chart_host self.scene_uri = scene_uri self.job = job self.display_pid = None self.host.run(['rm', '-f', self.OUTPUT_LOG], ignore_status=True) def initialize(self): """Prepare scene file and display it on chart host.""" logging.info('Prepare scene file') chart_version = self.host.run( 'cat /etc/lsb-release | grep CHROMEOS_RELEASE_BUILDER_PATH') logging.info('Chart version: %s', chart_version) if utils.is_in_container(): # Reboot chart to clean the dirty state from last test. See # b/201032899. version = self.host.get_release_builder_path() self.job.run_test('provision_QuickProvision', host=self.host, value=version, force_update_engine=True) tmpdir = self.host.get_tmp_dir() scene_path = os.path.join( tmpdir, self.scene_uri[self.scene_uri.rfind('/') + 1:]) self.host.run('wget', args=('-O', scene_path, self.scene_uri)) logging.info('Display scene file') self.display_pid = self.host.run_background( 'python {script} {scene} >{log} 2>&1'.format( script=self.DISPLAY_SCRIPT, scene=scene_path, log=self.OUTPUT_LOG)) logging.info( 'Poll for "is ready" message for ensuring chart is ready.') timeout = 60 poll_time_step = 0.1 while timeout > 0: if self.host.run( 'grep', args=('-q', 'Chart is ready.', self.OUTPUT_LOG), ignore_status=True).exit_status == 0: break time.sleep(poll_time_step) timeout -= poll_time_step else: raise error.TestError('Timeout waiting for chart ready') def cleanup(self): """Cleanup display script.""" if self.display_pid is not None: self.host.run( 'kill', args=('-2', str(self.display_pid)), ignore_status=True) self.host.get_file(self.OUTPUT_LOG, '.') def get_chart_address(host_address, args): """Get address of chart tablet from commandline args or mapping logic in test lab. @param host_address: a list of hostname strings. @param args: a dict parse from commandline args. @return: A list of strings for chart tablet addresses. """ address = utils.args_to_dict(args).get('chart') if address is not None: return address.split(',') elif utils.is_in_container(): return [utils.get_lab_chart_address(host) for host in host_address] else: return None class DUTFixture: """Sets up camera filter for target camera facing on DUT.""" TEST_CONFIG_PATH = '/var/cache/camera/test_config.json' CAMERA_SCENE_LOG = '/tmp/scene.jpg' def __init__(self, test, host, facing): self.test = test self.host = host self.facing = facing @contextlib.contextmanager def _set_selinux_permissive(self): selinux_mode = self.host.run_output('getenforce') self.host.run('setenforce 0') yield self.host.run('setenforce', args=(selinux_mode, )) def _write_file(self, filepath, content, permission=None, owner=None): """Write content to filepath on remote host. @param permission: set permission to 0xxx octal number of remote file. @param owner: set owner of remote file. """ tmp_path = os.path.join(self.test.tmpdir, os.path.basename(filepath)) with open(tmp_path, 'w') as f: f.write(content) if permission is not None: os.chmod(tmp_path, permission) self.host.send_file(tmp_path, filepath, delete_dest=True) if owner is not None: self.host.run('chown', args=(owner, filepath)) def initialize(self): """Filter out camera other than target facing on DUT.""" self._write_file( self.TEST_CONFIG_PATH, json.dumps({ 'enable_back_camera': self.facing == 'back', 'enable_front_camera': self.facing == 'front', 'enable_external_camera': False }), owner='arc-camera') # cros_camera_service will reference the test config to filter out # undesired cameras. logging.info('Restart camera service with filter option') self.host.upstart_restart('cros-camera') # arc_setup will reference the test config to filter out the media # profile of undesired cameras. logging.info('Restart ARC++ container with camera test config') self.host.run('restart ui') @contextlib.contextmanager def _stop_camera_service(self): # Ensure camera service is running or the # upstart_stop()/upstart_restart() may failed due to in # "start|post-stop" sleep for respawning state. See b/183904344 for # detail. logging.info('Wait for presence of camera service') self.host.wait_for_service('cros-camera') self.host.upstart_stop('cros-camera') yield self.host.upstart_restart('cros-camera') def log_camera_scene(self): """Capture an image from camera as the log for debugging scene related problem.""" gtest_filter = ( 'Camera3StillCaptureTest/' 'Camera3DumpSimpleStillCaptureTest.DumpCaptureResult/0') with self._stop_camera_service(): self.host.run( 'sudo', args=('--user=arc-camera', 'cros_camera_test', '--gtest_filter=' + gtest_filter, '--camera_facing=' + self.facing, '--dump_still_capture_path=' + self.CAMERA_SCENE_LOG)) self.host.get_file(self.CAMERA_SCENE_LOG, '.') def cleanup(self): """Cleanup camera filter.""" logging.info('Remove filter option and restore camera service') with self._stop_camera_service(): self.host.run('rm', args=('-f', self.TEST_CONFIG_PATH)) logging.info('Restore camera profile in ARC++ container') self.host.run('restart ui')