1# Copyright (c) 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.client.common_lib import error 10from autotest_lib.client.common_lib import file_utils 11from autotest_lib.client.common_lib.cros import system_metrics_collector 12from autotest_lib.server.cros.cfm import cfm_base_test 13from autotest_lib.server.cros.cfm.utils import bond_http_api 14from autotest_lib.server.cros.cfm.utils import perf_metrics_collector 15 16 17_BOT_PARTICIPANTS_COUNT = 10 18_TOTAL_TEST_DURATION_SECONDS = 15 * 60 # 15 minutes 19 20_DOWNLOAD_BASE = ('http://commondatastorage.googleapis.com/' 21 'chromiumos-test-assets-public/crowd/') 22_VIDEO_NAME = 'crowd720_25frames.y4m' 23 24 25class ParticipantCountMetric(system_metrics_collector.Metric): 26 """ 27 Metric for getting the current participant count in a call. 28 """ 29 def __init__(self, cfm_facade): 30 """ 31 Initializes with a cfm_facade. 32 33 @param cfm_facade object having a get_participant_count() method. 34 """ 35 super(ParticipantCountMetric, self).__init__( 36 'participant_count', 37 'participants', 38 higher_is_better=True) 39 self.cfm_facade = cfm_facade 40 41 def collect_metric(self): 42 """ 43 Collects one metric value. 44 """ 45 self.values.append(self.cfm_facade.get_participant_count()) 46 47class enterprise_CFM_Perf(cfm_base_test.CfmBaseTest): 48 """This is a server test which clears device TPM and runs 49 enterprise_RemoraRequisition client test to enroll the device in to hotrod 50 mode. After enrollment is successful, it collects and logs cpu, memory and 51 temperature data from the device under test.""" 52 version = 1 53 54 def _download_test_video(self): 55 """ 56 Downloads the test video to a temporary directory on host. 57 58 @return the remote path of the downloaded video. 59 """ 60 url = _DOWNLOAD_BASE + _VIDEO_NAME 61 local_path = os.path.join(self.tmpdir, _VIDEO_NAME) 62 logging.info('Downloading %s to %s', url, local_path) 63 file_utils.download_file(url, local_path) 64 # The directory returned by get_tmp_dir() is automatically deleted. 65 tmp_dir = self._host.get_tmp_dir() 66 remote_path = os.path.join(tmp_dir, _VIDEO_NAME) 67 # The temporary directory has mode 700 by default. Chrome runs with a 68 # different user so cannot access it unless we change the permissions. 69 logging.info('chmodding tmpdir %s to 755', tmp_dir) 70 self._host.run('chmod 755 %s' % tmp_dir) 71 logging.info('Sending %s to %s on DUT', local_path, remote_path) 72 self._host.send_file(local_path, remote_path) 73 os.remove(local_path) 74 return remote_path 75 76 def initialize(self, host, run_test_only=False, use_bond=True): 77 """ 78 Initializes common test properties. 79 80 @param host: a host object representing the DUT. 81 @param run_test_only: Whether to run only the test or to also perform 82 deprovisioning, enrollment and system reboot. See cfm_base_test. 83 @param use_bond: Whether to use BonD to add bots to the meeting. Useful 84 for local testing. 85 """ 86 super(enterprise_CFM_Perf, self).initialize(host, run_test_only) 87 self._host = host 88 self._use_bond = use_bond 89 system_facade = self._facade_factory.create_system_facade() 90 self._perf_metrics_collector = ( 91 perf_metrics_collector.PerfMetricsCollector( 92 system_facade, 93 self.cfm_facade, 94 self.output_perf_value, 95 additional_system_metrics=[ 96 ParticipantCountMetric(self.cfm_facade), 97 ])) 98 99 def setup(self): 100 """ 101 Download video for fake media and restart Chrome with fake media flags. 102 103 This runs after initialize(). 104 """ 105 super(enterprise_CFM_Perf, self).setup() 106 remote_video_path = self._download_test_video() 107 # Restart chrome with fake media flags. 108 extra_chrome_args=[ 109 '--use-fake-device-for-media-stream', 110 '--use-file-for-fake-video-capture=%s' % remote_video_path 111 ] 112 self.cfm_facade.restart_chrome_for_cfm(extra_chrome_args) 113 if self._use_bond: 114 self.bond = bond_http_api.BondHttpApi() 115 116 def run_once(self): 117 """Joins a meeting and collects perf data.""" 118 self.cfm_facade.wait_for_meetings_landing_page() 119 120 if self._use_bond: 121 meeting_code = self.bond.CreateConference() 122 logging.info('Started meeting "%s"', meeting_code) 123 self._add_bots(_BOT_PARTICIPANTS_COUNT, meeting_code) 124 self.cfm_facade.join_meeting_session(meeting_code) 125 else: 126 self.cfm_facade.start_meeting_session() 127 128 self.cfm_facade.unmute_mic() 129 130 self._perf_metrics_collector.start() 131 time.sleep(_TOTAL_TEST_DURATION_SECONDS) 132 self._perf_metrics_collector.stop() 133 134 self.cfm_facade.end_meeting_session() 135 self._perf_metrics_collector.upload_metrics() 136 137 def _add_bots(self, bot_count, meeting_code): 138 """Adds bots to a meeting and configures audio and pinning settings. 139 140 If we were not able to start enough bots end the test run. 141 """ 142 botIds = self.bond.AddBotsRequest( 143 meeting_code, 144 bot_count, 145 _TOTAL_TEST_DURATION_SECONDS + 30); 146 147 if len(botIds) < bot_count: 148 # If we did not manage to start enough bots, free up the 149 # resources and end the test run. 150 self.bond.ExecuteScript('@all leave', meeting_code) 151 raise error.TestNAError("Not enough bot resources.\n" 152 "Wanted: %d. Started: %d" % (bot_count, len(botIds))) 153 154 # Configure philosopher audio for one bot. 155 self._start_philosopher_audio(botIds[0], meeting_code) 156 157 # Pin the CfM from one bot so the device always sends HD. 158 self.bond.ExecuteScript( 159 '@b%d pin_participant_by_name "Unknown"' % botIds[0], meeting_code) 160 # Explicitly request HD video from the CfM. 161 self.bond.ExecuteScript( 162 '@b%d set_resolution 1280 720' % botIds[0], meeting_code) 163 164 def _start_philosopher_audio(self, bot_id, meeting_code): 165 self.bond.ExecuteScript( 166 '@b%d start_philosopher_audio' % bot_id, meeting_code) 167