Chrome on Chromeos Perf: Upload Results to Google Storage

Added a post-processing step to the pyauto_perf suite to upload the necessary
perf results back to the google storage directory we downloaded the build
artifacts from.

The perf results are placed in the form of pyauto_perf.results

BUG=chromium-os:33964
TEST=Tested on ToT using remote trybots.
CQ-DEPENDS: I2b993c7b561c2abae9ed2717515c9b394bcecfa5
Change-Id: I6af12674c3cfa031b6382e4cc3fe2f735743486a
Reviewed-on: https://gerrit.chromium.org/gerrit/34199
Commit-Ready: Simran Basi <sbasi@chromium.org>
Reviewed-by: Simran Basi <sbasi@chromium.org>
Tested-by: Simran Basi <sbasi@chromium.org>
diff --git a/client/common_lib/site_utils.py b/client/common_lib/site_utils.py
index ec84577..760e06b 100644
--- a/client/common_lib/site_utils.py
+++ b/client/common_lib/site_utils.py
@@ -1,6 +1,7 @@
 # Copyright (c) 2012 The Chromium 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 re
 import socket
 
@@ -62,3 +63,55 @@
             if m:
                 return m.group(1)
     return None
+
+
+# TODO(petermayo): crosbug.com/31826 Share this with _GsUpload in
+# //chromite.git/buildbot/prebuilt.py somewhere/somehow
+def gs_upload(local_file, remote_file, acl, result_dir=None,
+              transfer_timeout=300, acl_timeout=300):
+    """Upload to GS bucket.
+
+    @param local_file: Local file to upload
+    @param remote_file: Remote location to upload the local_file to.
+    @param acl: name or file used for controlling access to the uploaded
+                file.
+    @param result_dir: Result directory if you want to add tracing to the
+                       upload.
+
+    @raise CmdError: the exit code of the gsutil call was not 0.
+
+    @returns True/False - depending on if the upload succeeded or failed.
+    """
+    # https://developers.google.com/storage/docs/accesscontrol#extension
+    CANNED_ACLS = ['project-private', 'private', 'public-read',
+                   'public-read-write', 'authenticated-read',
+                   'bucket-owner-read', 'bucket-owner-full-control']
+    _GSUTIL_BIN = 'gsutil'
+    acl_cmd = None
+    if acl in CANNED_ACLS:
+        cmd = '%s cp -a %s %s %s' % (_GSUTIL_BIN, acl, local_file, remote_file)
+    else:
+        # For private uploads we assume that the overlay board is set up
+        # properly and a googlestore_acl.xml is present, if not this script
+        # errors
+        cmd = '%s cp -a private %s %s' % (_GSUTIL_BIN, local_file, remote_file)
+        if not os.path.exists(acl):
+            logging.error('Unable to find ACL File %s.', acl)
+            return False
+        acl_cmd = '%s setacl %s %s' % (_GSUTIL_BIN, acl, remote_file)
+    if not result_dir:
+        base_utils.run(cmd, timeout=transfer_timeout, verbose=True)
+        if acl_cmd:
+            base_utils.run(acl_cmd, timeout=acl_timeout, verbose=True)
+        return True
+    with open(os.path.join(result_dir, 'tracing'), 'w') as ftrace:
+        ftrace.write('Preamble\n')
+        base_utils.run(cmd, timeout=transfer_timeout, verbose=True,
+                       stdout_tee=ftrace, stderr_tee=ftrace)
+        if acl_cmd:
+            ftrace.write('\nACL setting\n')
+            # Apply the passed in ACL xml file to the uploaded object.
+            base_utils.run(acl_cmd, timeout=acl_timeout, verbose=True,
+                           stdout_tee=ftrace, stderr_tee=ftrace)
+        ftrace.write('Postamble\n')
+        return True
diff --git a/server/site_tests/chromeperf_PGOPageCycler/chromeperf_PGOPageCycler.py b/server/site_tests/chromeperf_PGOPageCycler/chromeperf_PGOPageCycler.py
index c0e65f5..0fda06a 100644
--- a/server/site_tests/chromeperf_PGOPageCycler/chromeperf_PGOPageCycler.py
+++ b/server/site_tests/chromeperf_PGOPageCycler/chromeperf_PGOPageCycler.py
@@ -50,53 +50,6 @@
         self.extra_args = extras
 
 
-    # TODO(petermayo): crosbug.com/31826 Share this with _GsUpload in
-    # //chromite.git/buildbot/prebuilt.py somewhere/somehow.
-    def _gs_upload(self, local_file, remote_file, acl):
-        """Upload to GS bucket.
-
-        Args:
-            local_file
-            remote_file
-            acl name or file used for controlling access to the uploaded file.
-
-        Returns:
-            Return the arg tuple of two if the upload failed
-        """
-
-        # https://developers.google.com/storage/docs/accesscontrol#extension
-        CANNED_ACLS = ['project-private', 'private', 'public-read',
-                       'public-read-write', 'authenticated-read',
-                       'bucket-owner-read', 'bucket-owner-full-control']
-        _GSUTIL_BIN = 'gsutil'
-
-        acl_cmd = None
-        if acl in CANNED_ACLS:
-            cmd = [_GSUTIL_BIN, 'cp', '-a', acl, local_file, remote_file]
-        else:
-            # For private uploads we assume that the overlay board is set up
-            # properly and a googlestore_acl.xml is present, if not this script
-            # errors
-            cmd = [_GSUTIL_BIN, 'cp', '-a', 'private', local_file, remote_file]
-            if not os.path.exists(acl):
-                raise error.TestFail('Unresolved acl %s.' % acl)
-            acl_cmd = [_GSUTIL_BIN, 'setacl', acl, remote_file]
-
-        with open(os.path.join(self.job.resultdir, 'tracing'), 'w') as ftrace:
-            ftrace.write('Preamble\n')
-            utils.run(cmd[0], args=cmd[1:], timeout=self._PGO_TRANSFER_TIMEOUT,
-                      verbose=True, stdout_tee=ftrace, stderr_tee=ftrace)
-
-            if acl_cmd:
-                ftrace.write('\nACL setting\n')
-                # Apply the passed in ACL xml file to the uploaded object.
-                utils.run(acl_cmd[0], args=acl_cmd[1:],
-                          timeout=self._ACL_SET_TIMEOUT,
-                          verbose=True, stdout_tee=ftrace, stderr_tee=ftrace)
-
-            ftrace.write('Postamble\n')
-
-
     def run_once(self, host=None, args=[]):
         self.parse_args(args)
 
@@ -134,7 +87,7 @@
                     with open(verfile, 'r') as f:
                         self.options.destination = f.read().strip()
             if self.options.destination:
-                if self._gs_upload(src, self.options.destination,
-                                   self.options.acl) is not None:
+                if not utils.gs_upload(src, self.options.destination,
+                        self.options.acl, result_dir=self.job.resultdir)
                     raise error.TestFail('Unable to copy from %s to %s' %
                                          (src, self.options.destination))
diff --git a/server/site_tests/desktopui_PyAutoPerf/control b/server/site_tests/desktopui_PyAutoPerf/control
new file mode 100644
index 0000000..3843881
--- /dev/null
+++ b/server/site_tests/desktopui_PyAutoPerf/control
@@ -0,0 +1,25 @@
+# Copyright (c) 2012 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.
+
+AUTHOR = "Chrome OS Team"
+NAME = "PyAuto Perf"
+SUITE = "pyauto_perf"
+TIME = "LONG"
+TEST_CATEGORY = "Functional"
+TEST_CLASS = "suite"
+TEST_TYPE = "server"
+
+DOC = """
+This server side test suite wraps the client-side PyAuto-based performance
+tests and uploads the performance result values to google storage so that
+they can be displayed easily on the performance dashboard. This is part of
+our effort to support Chrome for Chrome OS performance testing.
+"""
+
+def run_pyautoperftests(machine):
+    host = hosts.create_host(machine)
+    job.run_test("desktopui_PyAutoPerf", host=host, args=args)
+
+
+parallel_simple(run_pyautoperftests, machines)
diff --git a/server/site_tests/desktopui_PyAutoPerf/desktopui_PyAutoPerf.py b/server/site_tests/desktopui_PyAutoPerf/desktopui_PyAutoPerf.py
new file mode 100644
index 0000000..8819306
--- /dev/null
+++ b/server/site_tests/desktopui_PyAutoPerf/desktopui_PyAutoPerf.py
@@ -0,0 +1,36 @@
+# Copyright (c) 2012 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 subprocess
+
+from autotest_lib.client.common_lib import utils
+from autotest_lib.server import test, autotest
+
+
+class desktopui_PyAutoPerf(test.test):
+    version = 1
+    _GS_PATH_FORMAT = 'gs://chromeos-image-archive/%s/%s/pyauto_perf.results'
+
+
+    def run_once(self, host=None, args=[]):
+        self.client = host
+        self.client_test = 'desktopui_PyAutoPerfTests'
+        self.server_test = 'desktopui_PyAutoPerf'
+        client_at = autotest.Autotest(self.client)
+        client_at.run_test(self.client_test, args=str(args))
+        if not self.job.label:
+            logging.debug('Job has no label, therefore not uploading perf'
+                          ' results to google storage.')
+            return
+        # The label is in the format of builder/build/suite/test
+        result_file = os.path.join(self.job.resultdir, self.server_test,
+                                   self.client_test, 'results', 'keyval')
+        builder,build = self.job.label.split('/')[0:2]
+        gs_path = self._GS_PATH_FORMAT % (builder, build)
+        if not utils.gs_upload(result_file, gs_path, 'project-private'):
+            raise error.TestFail('Failed to upload perf results %s to google'
+                                 'storage location %s.' % (result_file,
+                                                           gs_path))
\ No newline at end of file
diff --git a/server/site_tests/suites/control.desktopui_pyauto_perf b/server/site_tests/suites/control.desktopui_pyauto_perf
deleted file mode 100644
index dc2742f..0000000
--- a/server/site_tests/suites/control.desktopui_pyauto_perf
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (c) 2012 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.
-
-AUTHOR = "Chrome OS Team"
-NAME = "PyAuto Perf"
-SUITE = "pyauto_perf"
-TIME = "LONG"
-TEST_CATEGORY = "Functional"
-TEST_CLASS = "suite"
-TEST_TYPE = "server"
-
-DOC = """
-This test suite runs PyAuto-based performance tests.
-"""
-
-gtest_runner.run(('desktopui_PyAutoPerfTests', {}), machines[0])