[autotest][cfm] Migrates the CfM perf test to use bond

Changes include:
- every perf run starts a new meeting instead of joining the same one
- starting a meeting session now returns the meeting code
- bot count has been reduced to 20
  - after a f2f discussion with dancarregosa@ about the test case we
concluded there was no difference between 20 and e.g. 50 for this use
case
- 1 bot now sends audio to cause more load
- 1 bot now pins the CfM to enforce HD

BUG=b:116194847
TEST=local setup

Change-Id: I3ada731a2f761c40140e85f689b314895d048e2f
Reviewed-on: https://chromium-review.googlesource.com/1276525
Commit-Ready: Denis Tosic <dtosic@google.com>
Tested-by: Denis Tosic <dtosic@google.com>
Reviewed-by: Kristoffer Erlandsson <kerl@google.com>
diff --git a/client/common_lib/cros/cfm_meetings_api.py b/client/common_lib/cros/cfm_meetings_api.py
index 12f20a6..1f28a4e 100644
--- a/client/common_lib/cros/cfm_meetings_api.py
+++ b/client/common_lib/cros/cfm_meetings_api.py
@@ -4,6 +4,8 @@
 
 import logging
 
+from urlparse import urlparse
+
 DEFAULT_TIMEOUT = 30
 TELEMETRY_API = 'hrTelemetryApi'
 
@@ -58,13 +60,23 @@
 
     # Hangouts commands/functions
     def start_meeting_session(self):
-        """Start a meeting."""
+        """Start a meeting.
+
+        @return code for the started meeting
+        """
         if self.is_in_meeting_session():
             self.end_meeting_session()
 
         self._execute_telemetry_command('startMeeting()')
         self.wait_for_meetings_in_call_page()
-        logging.info('Started meeting session.')
+        meeting_code = self._get_meeting_code()
+        logging.info('Started meeting session %s', meeting_code)
+        return meeting_code
+
+    def _get_meeting_code(self):
+        path = urlparse(self._webview_context.GetUrl()).path
+        # The meeting code is the last part of the path.
+        return path.split('/')[-1]
 
     def join_meeting_session(self, meeting_name):
         """Joins a meeting.
diff --git a/client/cros/multimedia/cfm_facade_native.py b/client/cros/multimedia/cfm_facade_native.py
index f9d1c8e..fe629ba 100644
--- a/client/cros/multimedia/cfm_facade_native.py
+++ b/client/cros/multimedia/cfm_facade_native.py
@@ -321,8 +321,11 @@
 
 
     def start_meeting_session(self):
-        """Start a meeting."""
-        self._cfmApi.start_meeting_session()
+        """Start a meeting.
+
+        @return code for the started meeting
+        """
+        return self._cfmApi.start_meeting_session()
 
 
     def end_meeting_session(self):
diff --git a/server/cros/multimedia/cfm_facade_adapter.py b/server/cros/multimedia/cfm_facade_adapter.py
index 4e934da..38b5423 100644
--- a/server/cros/multimedia/cfm_facade_adapter.py
+++ b/server/cros/multimedia/cfm_facade_adapter.py
@@ -184,8 +184,11 @@
 
 
     def start_meeting_session(self):
-        """Start a meeting."""
-        self._cfm_proxy.start_meeting_session()
+        """Start a meeting.
+
+        @return code for the started meeting.
+        """
+        return self._cfm_proxy.start_meeting_session()
 
 
     def end_meeting_session(self):
diff --git a/server/site_tests/enterprise_CFM_Perf/enterprise_CFM_Perf.py b/server/site_tests/enterprise_CFM_Perf/enterprise_CFM_Perf.py
index 0a2c94f..0ef38e9 100644
--- a/server/site_tests/enterprise_CFM_Perf/enterprise_CFM_Perf.py
+++ b/server/site_tests/enterprise_CFM_Perf/enterprise_CFM_Perf.py
@@ -15,10 +15,13 @@
         media_metrics_collector)
 from autotest_lib.server.cros import cfm_jmidata_log_collector
 from autotest_lib.server.cros.cfm import cfm_base_test
+from autotest_lib.server.cros.cfm.utils import bond_http_api
+
 
 _SHORT_TIMEOUT = 5
 _MEASUREMENT_DURATION_SECONDS = 10
-_TOTAL_TEST_DURATION_SECONDS = 900
+_TOTAL_TEST_DURATION_SECONDS = 900 # 15 minutes
+_BOT_PARTICIPANTS_COUNT = 20
 
 _DOWNLOAD_BASE = ('http://commondatastorage.googleapis.com/'
                   'chromiumos-test-assets-public/crowd/')
@@ -29,6 +32,7 @@
 _JMI_DIR = '/0*/File\ System/000/t/00/*'
 _JMI_SOURCE_DIR = _BASE_DIR + _EXT_ID + _JMI_DIR
 
+
 class ParticipantCountMetric(system_metrics_collector.Metric):
     """
     Metric for getting the current participant count in a call.
@@ -67,13 +71,13 @@
         self.cfm_facade.start_new_hangout_session(hangout_name)
 
 
-    def join_meeting(self):
-        """Waits for the landing page and joins a meeting session."""
-        self.cfm_facade.wait_for_meetings_landing_page()
-        # Daily meeting for perf testing with 9 remote participants.
-        meeting_code = 'nis-rhmz-dyh'
-        self.cfm_facade.join_meeting_session(meeting_code)
+    def start_meeting(self):
+        """Waits for the landing page and starts a meeting.
 
+        @return: The code for the started meeting.
+        """
+        self.cfm_facade.wait_for_meetings_landing_page()
+        return self.cfm_facade.start_meeting_session()
 
     def collect_perf_data(self):
         """
@@ -359,12 +363,15 @@
                 '--use-file-for-fake-video-capture=%s' % remote_video_path
         ]
         self.cfm_facade.restart_chrome_for_cfm(extra_chrome_args)
+        self.bond = bond_http_api.BondHttpApi()
 
     def run_once(self, is_meeting=False):
         """Stays in a meeting/hangout and collects perf data."""
         self.is_meeting = is_meeting
         if is_meeting:
-            self.join_meeting()
+            meeting_code = self.start_meeting()
+            logging.info('Started meeting "%s"', meeting_code)
+            self._add_bots(_BOT_PARTICIPANTS_COUNT, meeting_code)
         else:
             self.start_hangout()
         self.cfm_facade.unmute_mic()
@@ -378,3 +385,31 @@
 
         self.upload_jmidata()
 
+    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 (this room)"' % 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)