| # Copyright (c) 2017 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 |
| import os |
| import time |
| |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.common_lib import file_utils |
| from autotest_lib.client.common_lib.cros import system_metrics_collector |
| from autotest_lib.server.cros.cfm import cfm_base_test |
| from autotest_lib.server.cros.cfm.utils import bond_http_api |
| from autotest_lib.server.cros.cfm.utils import perf_metrics_collector |
| |
| |
| _BOT_PARTICIPANTS_COUNT = 10 |
| _TOTAL_TEST_DURATION_SECONDS = 15 * 60 # 15 minutes |
| |
| _DOWNLOAD_BASE = ('http://commondatastorage.googleapis.com/' |
| 'chromiumos-test-assets-public/crowd/') |
| _VIDEO_NAME = 'crowd720_25frames.y4m' |
| |
| |
| class ParticipantCountMetric(system_metrics_collector.Metric): |
| """ |
| Metric for getting the current participant count in a call. |
| """ |
| def __init__(self, cfm_facade): |
| """ |
| Initializes with a cfm_facade. |
| |
| @param cfm_facade object having a get_participant_count() method. |
| """ |
| super(ParticipantCountMetric, self).__init__( |
| 'participant_count', |
| 'participants', |
| higher_is_better=True) |
| self.cfm_facade = cfm_facade |
| |
| def collect_metric(self): |
| """ |
| Collects one metric value. |
| """ |
| self.values.append(self.cfm_facade.get_participant_count()) |
| |
| class enterprise_CFM_Perf(cfm_base_test.CfmBaseTest): |
| """This is a server test which clears device TPM and runs |
| enterprise_RemoraRequisition client test to enroll the device in to hotrod |
| mode. After enrollment is successful, it collects and logs cpu, memory and |
| temperature data from the device under test.""" |
| version = 1 |
| |
| def _download_test_video(self): |
| """ |
| Downloads the test video to a temporary directory on host. |
| |
| @return the remote path of the downloaded video. |
| """ |
| url = _DOWNLOAD_BASE + _VIDEO_NAME |
| local_path = os.path.join(self.tmpdir, _VIDEO_NAME) |
| logging.info('Downloading %s to %s', url, local_path) |
| file_utils.download_file(url, local_path) |
| # The directory returned by get_tmp_dir() is automatically deleted. |
| tmp_dir = self._host.get_tmp_dir() |
| remote_path = os.path.join(tmp_dir, _VIDEO_NAME) |
| # The temporary directory has mode 700 by default. Chrome runs with a |
| # different user so cannot access it unless we change the permissions. |
| logging.info('chmodding tmpdir %s to 755', tmp_dir) |
| self._host.run('chmod 755 %s' % tmp_dir) |
| logging.info('Sending %s to %s on DUT', local_path, remote_path) |
| self._host.send_file(local_path, remote_path) |
| os.remove(local_path) |
| return remote_path |
| |
| def initialize(self, host, run_test_only=False, use_bond=True): |
| """ |
| Initializes common test properties. |
| |
| @param host: a host object representing the DUT. |
| @param run_test_only: Whether to run only the test or to also perform |
| deprovisioning, enrollment and system reboot. See cfm_base_test. |
| @param use_bond: Whether to use BonD to add bots to the meeting. Useful |
| for local testing. |
| """ |
| super(enterprise_CFM_Perf, self).initialize(host, run_test_only) |
| self._host = host |
| self._use_bond = use_bond |
| system_facade = self._facade_factory.create_system_facade() |
| self._perf_metrics_collector = ( |
| perf_metrics_collector.PerfMetricsCollector( |
| system_facade, |
| self.cfm_facade, |
| self.output_perf_value, |
| additional_system_metrics=[ |
| ParticipantCountMetric(self.cfm_facade), |
| ])) |
| |
| def setup(self): |
| """ |
| Download video for fake media and restart Chrome with fake media flags. |
| |
| This runs after initialize(). |
| """ |
| super(enterprise_CFM_Perf, self).setup() |
| remote_video_path = self._download_test_video() |
| # Restart chrome with fake media flags. |
| extra_chrome_args=[ |
| '--use-fake-device-for-media-stream', |
| '--use-file-for-fake-video-capture=%s' % remote_video_path |
| ] |
| self.cfm_facade.restart_chrome_for_cfm(extra_chrome_args) |
| if self._use_bond: |
| self.bond = bond_http_api.BondHttpApi() |
| |
| def run_once(self): |
| """Joins a meeting and collects perf data.""" |
| self.cfm_facade.wait_for_meetings_landing_page() |
| |
| if self._use_bond: |
| meeting_code = self.bond.CreateConference() |
| logging.info('Started meeting "%s"', meeting_code) |
| self._add_bots(_BOT_PARTICIPANTS_COUNT, meeting_code) |
| self.cfm_facade.join_meeting_session(meeting_code) |
| else: |
| self.cfm_facade.start_meeting_session() |
| |
| self.cfm_facade.unmute_mic() |
| |
| self._perf_metrics_collector.start() |
| time.sleep(_TOTAL_TEST_DURATION_SECONDS) |
| self._perf_metrics_collector.stop() |
| |
| self.cfm_facade.end_meeting_session() |
| self._perf_metrics_collector.upload_metrics() |
| |
| def _add_bots(self, bot_count, meeting_code): |
| """Adds bots to a meeting and configures audio and pinning settings. |
| |
| If we were not able to start enough bots end the test run. |
| """ |
| botIds = self.bond.AddBotsRequest( |
| meeting_code, |
| bot_count, |
| _TOTAL_TEST_DURATION_SECONDS + 30); |
| |
| if len(botIds) < bot_count: |
| # If we did not manage to start enough bots, free up the |
| # resources and end the test run. |
| self.bond.ExecuteScript('@all leave', meeting_code) |
| raise error.TestNAError("Not enough bot resources.\n" |
| "Wanted: %d. Started: %d" % (bot_count, len(botIds))) |
| |
| # Configure philosopher audio for one bot. |
| self._start_philosopher_audio(botIds[0], meeting_code) |
| |
| # Pin the CfM from one bot so the device always sends HD. |
| self.bond.ExecuteScript( |
| '@b%d pin_participant_by_name "Unknown"' % botIds[0], meeting_code) |
| # Explicitly request HD video from the CfM. |
| self.bond.ExecuteScript( |
| '@b%d set_resolution 1280 720' % botIds[0], meeting_code) |
| |
| def _start_philosopher_audio(self, bot_id, meeting_code): |
| self.bond.ExecuteScript( |
| '@b%d start_philosopher_audio' % bot_id, meeting_code) |