• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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