results.webkit.org: Start reporting results
https://bugs.webkit.org/show_bug.cgi?id=202639

Reviewed by Dewei Zhu.

* BuildSlaveSupport/build.webkit.org-config/loadConfig.py:
(loadBuilderConfig): Load API key for results.webkit.org.
* BuildSlaveSupport/build.webkit.org-config/make_passwords_json.py:
(create_mock_slave_passwords_dict): Add mock for API key.
* BuildSlaveSupport/build.webkit.org-config/steps.py:
(RunWebKitTests): Start reporting to results.webkit.org.
(RunWebKitTests.__init__): Do not print the environment to hide the API key.
(RunWebKitTests.start): Add the API key to the environment.
(RunAPITests): Start reporting to results.webkit.org.
(RunAPITests.__init__): Do not print the environment to hide the API key.
(RunAPITests.start): Add the API key to the environment.
(RunPythonTests): Start reporting to results.webkit.org.
(RunPythonTests.__init__): Do not print the environment to hide the API key.
(RunPythonTests.start): Add the API key to the environment.
* Scripts/webkitpy/results/upload.py:
(Upload):
(Upload.upload): Add API_KEY, if it exists, to the request.
(Upload.upload_archive): Ditto.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@250966 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/loadConfig.py b/Tools/BuildSlaveSupport/build.webkit.org-config/loadConfig.py
index 297640e..b888425 100644
--- a/Tools/BuildSlaveSupport/build.webkit.org-config/loadConfig.py
+++ b/Tools/BuildSlaveSupport/build.webkit.org-config/loadConfig.py
@@ -49,8 +49,11 @@
         passwords = make_passwords_json.create_mock_slave_passwords_dict()
     else:
         passwords = json.load(open('passwords.json'))
-    config = json.load(open('config.json'))
+    results_server_api_key = passwords.get('results-server-api-key')
+    if results_server_api_key:
+        os.environ['RESULTS_SERVER_API_KEY'] = results_server_api_key
 
+    config = json.load(open('config.json'))
     c['slaves'] = [BuildSlave(slave['name'], passwords[slave['name']], max_builds=1) for slave in config['slaves']]
 
     c['schedulers'] = []
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/make_passwords_json.py b/Tools/BuildSlaveSupport/build.webkit.org-config/make_passwords_json.py
index 35aebd8..9c79813 100755
--- a/Tools/BuildSlaveSupport/build.webkit.org-config/make_passwords_json.py
+++ b/Tools/BuildSlaveSupport/build.webkit.org-config/make_passwords_json.py
@@ -31,7 +31,9 @@
 def create_mock_slave_passwords_dict():
     with open('config.json', 'r') as config_json:
         config_dict = json.load(config_json)
-    return dict([(slave['name'], '1234') for slave in config_dict['slaves']])
+    result = dict([(slave['name'], '1234') for slave in config_dict['slaves']])
+    result['results-server-api-key'] = 'api-key'
+    return result
 
 if __name__ == '__main__':
     with open('passwords.json', 'w') as passwords_file:
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/steps.py b/Tools/BuildSlaveSupport/build.webkit.org-config/steps.py
index a3d85af..bd46c84 100644
--- a/Tools/BuildSlaveSupport/build.webkit.org-config/steps.py
+++ b/Tools/BuildSlaveSupport/build.webkit.org-config/steps.py
@@ -35,6 +35,8 @@
 APPLE_WEBKIT_AWS_PROXY = "http://proxy01.webkit.org:3128"
 S3URL = "https://s3-us-west-2.amazonaws.com/"
 WithProperties = properties.WithProperties
+RESULTS_WEBKIT = 'https://results.webkit.org'
+RESULTS_SERVER_API_KEY = 'RESULTS_SERVER_API_KEY'
 
 
 class TestWithFailureCount(shell.Test):
@@ -416,13 +418,22 @@
                "--clobber-old-results",
                "--builder-name", WithProperties("%(buildername)s"),
                "--build-number", WithProperties("%(buildnumber)s"),
+               "--buildbot-worker", WithProperties("%(slavename)s"),
                "--master-name", "webkit.org",
+               "--buildbot-master", "build.webkit.org",
+               "--report", RESULTS_WEBKIT,
                "--test-results-server", "webkit-test-results.webkit.org",
                "--exit-after-n-crashes-or-timeouts", "50",
                "--exit-after-n-failures", "500",
                WithProperties("--%(configuration)s")]
 
+    def __init__(self, *args, **kwargs):
+        kwargs['logEnviron'] = False
+        shell.Test.__init__(self, *args, **kwargs)
+
     def start(self):
+        self.slaveEnvironment[RESULTS_SERVER_API_KEY] = os.getenv(RESULTS_SERVER_API_KEY)
+
         platform = self.getProperty('platform')
         appendCustomTestingFlags(self, platform, self.getProperty('device_model'))
         additionalArguments = self.getProperty('additionalArguments')
@@ -530,10 +541,26 @@
     name = "run-api-tests"
     description = ["api tests running"]
     descriptionDone = ["api-tests"]
-    command = ["python", "./Tools/Scripts/run-api-tests", "--no-build", WithProperties("--%(configuration)s"), "--verbose"]
+    command = [
+        "python",
+        "./Tools/Scripts/run-api-tests",
+        "--no-build",
+        WithProperties("--%(configuration)s"),
+        "--verbose",
+        "--buildbot-master", "build.webkit.org",
+        "--builder-name", WithProperties("%(buildername)s"),
+        "--build-number", WithProperties("%(buildnumber)s"),
+        "--buildbot-worker", WithProperties("%(slavename)s"),
+        "--report", RESULTS_WEBKIT,
+    ]
     failedTestsFormatString = "%d api test%s failed or timed out"
 
+    def __init__(self, *args, **kwargs):
+        kwargs['logEnviron'] = False
+        TestWithFailureCount.__init__(self, *args, **kwargs)
+
     def start(self):
+        self.slaveEnvironment[RESULTS_SERVER_API_KEY] = os.getenv(RESULTS_SERVER_API_KEY)
         appendCustomTestingFlags(self, self.getProperty('platform'), self.getProperty('device_model'))
         return shell.Test.start(self)
 
@@ -550,10 +577,26 @@
     name = "webkitpy-test"
     description = ["python-tests running"]
     descriptionDone = ["python-tests"]
-    command = ["python", "./Tools/Scripts/test-webkitpy", "--verbose", WithProperties("--%(configuration)s")]
+    command = [
+        "python",
+        "./Tools/Scripts/test-webkitpy",
+        "--verbose",
+        WithProperties("--%(configuration)s"),
+        "--buildbot-master", "build.webkit.org",
+        "--builder-name", WithProperties("%(buildername)s"),
+        "--build-number", WithProperties("%(buildnumber)s"),
+        "--buildbot-worker", WithProperties("%(slavename)s"),
+        "--report", RESULTS_WEBKIT,
+    ]
     failedTestsFormatString = "%d python test%s failed"
 
+    def __init__(self, *args, **kwargs):
+        kwargs['logEnviron'] = False
+        TestWithFailureCount.__init__(self, *args, **kwargs)
+
     def start(self):
+        self.slaveEnvironment[RESULTS_SERVER_API_KEY] = os.getenv(RESULTS_SERVER_API_KEY)
+
         platform = self.getProperty('platform')
         # Python tests are flaky on the GTK builders, running them serially
         # helps and does not significantly prolong the cycle time.
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index 15b313f..871cb8b 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,29 @@
+2019-10-10  Jonathan Bedard  <jbedard@apple.com>
+
+        results.webkit.org: Start reporting results
+        https://bugs.webkit.org/show_bug.cgi?id=202639
+
+        Reviewed by Dewei Zhu.
+
+        * BuildSlaveSupport/build.webkit.org-config/loadConfig.py:
+        (loadBuilderConfig): Load API key for results.webkit.org.
+        * BuildSlaveSupport/build.webkit.org-config/make_passwords_json.py:
+        (create_mock_slave_passwords_dict): Add mock for API key.
+        * BuildSlaveSupport/build.webkit.org-config/steps.py:
+        (RunWebKitTests): Start reporting to results.webkit.org.
+        (RunWebKitTests.__init__): Do not print the environment to hide the API key.
+        (RunWebKitTests.start): Add the API key to the environment.
+        (RunAPITests): Start reporting to results.webkit.org.
+        (RunAPITests.__init__): Do not print the environment to hide the API key.
+        (RunAPITests.start): Add the API key to the environment.
+        (RunPythonTests): Start reporting to results.webkit.org.
+        (RunPythonTests.__init__): Do not print the environment to hide the API key.
+        (RunPythonTests.start): Add the API key to the environment.
+        * Scripts/webkitpy/results/upload.py:
+        (Upload):
+        (Upload.upload): Add API_KEY, if it exists, to the request.
+        (Upload.upload_archive): Ditto.
+
 2019-10-09  Russell Epstein  <repstein@apple.com>
 
         Unreviewed, rolling out r250930.
diff --git a/Tools/Scripts/webkitpy/results/upload.py b/Tools/Scripts/webkitpy/results/upload.py
index ab74cc8..b7c79fa 100644
--- a/Tools/Scripts/webkitpy/results/upload.py
+++ b/Tools/Scripts/webkitpy/results/upload.py
@@ -22,6 +22,7 @@
 
 import webkitpy.thirdparty.autoinstalled.requests
 
+import os
 import json
 import requests
 import sys
@@ -31,6 +32,7 @@
 
 
 class Upload(object):
+    API_KEY = os.getenv('RESULTS_SERVER_API_KEY')
     UPLOAD_ENDPOINT = '/api/upload'
     ARCHIVE_UPLOAD_ENDPOINT = '/api/upload/archive'
     BUILDBOT_DETAILS = ['buildbot-master', 'builder-name', 'build-number', 'buildbot-worker']
@@ -169,7 +171,14 @@
 
     def upload(self, hostname, log_line_func=lambda val: sys.stdout.write(val + '\n')):
         try:
-            response = requests.post('{}{}'.format(hostname, self.UPLOAD_ENDPOINT), data=json.dumps(self, cls=Upload.Encoder))
+            data = Upload.Encoder().default(self)
+            if self.API_KEY:
+                data['api_key'] = self.API_KEY
+            response = requests.post(
+                '{}{}'.format(hostname, self.UPLOAD_ENDPOINT),
+                headers={'Content-type': 'application/json'},
+                data=json.dumps(data),
+            )
         except requests.exceptions.ConnectionError:
             log_line_func(' ' * 4 + 'Failed to upload to {}, results server not online'.format(hostname))
             return False
@@ -179,7 +188,11 @@
 
         if response.status_code != 200:
             log_line_func(' ' * 4 + 'Error uploading to {}'.format(hostname))
-            log_line_func(' ' * 8 + response.json().get('description'))
+            try:
+                log_line_func(' ' * 8 + response.json().get('description'))
+            except ValueError:
+                for line in response.text.splitlines():
+                    log_line_func(' ' * 8 + line)
             return False
 
         log_line_func(' ' * 4 + 'Uploaded results to {}'.format(hostname))
@@ -195,6 +208,9 @@
             )
             if self.timestamp:
                 meta_data['timestamp'] = self.timestamp
+            if self.API_KEY:
+                meta_data['api_key'] = self.API_KEY
+            meta_data['Content-type'] = 'application/octet-stream'
             response = requests.post(
                 '{}{}'.format(hostname, self.ARCHIVE_UPLOAD_ENDPOINT),
                 data=meta_data,
@@ -208,9 +224,14 @@
             log_line_func(' ' * 4 + 'Failed to encode archive reference data: {}'.format(e))
             return False
 
-        if response.status_code != 200:
+        # FIXME: <rdar://problem/56154412> do not fail test runs because of 403 errors
+        if response.status_code not in [200, 403]:
             log_line_func(' ' * 4 + 'Error uploading archive to {}'.format(hostname))
-            log_line_func(' ' * 8 + response.json().get('description'))
+            try:
+                log_line_func(' ' * 8 + response.json().get('description'))
+            except ValueError:
+                for line in response.text.splitlines():
+                    log_line_func(' ' * 8 + line)
             return False
 
         log_line_func(' ' * 4 + 'Uploaded test archive to {}'.format(hostname))
diff --git a/Tools/Scripts/webkitpy/results/upload_unittest.py b/Tools/Scripts/webkitpy/results/upload_unittest.py
index 19b4067..41fa1cd 100644
--- a/Tools/Scripts/webkitpy/results/upload_unittest.py
+++ b/Tools/Scripts/webkitpy/results/upload_unittest.py
@@ -126,15 +126,15 @@
             )],
         )
 
-        with mock.patch('requests.post', new=lambda url, data: self.MockResponse()):
+        with mock.patch('requests.post', new=lambda url, headers={}, data={}: self.MockResponse()):
             self.assertTrue(upload.upload('https://results.webkit.org', log_line_func=lambda _: None))
 
-        with mock.patch('requests.post', new=lambda url, data: self.raise_requests_ConnectionError()):
+        with mock.patch('requests.post', new=lambda url, headers={}, data={}: self.raise_requests_ConnectionError()):
             lines = []
             self.assertFalse(upload.upload('https://results.webkit.org', log_line_func=lambda line: lines.append(line)))
             self.assertEqual([' ' * 4 + 'Failed to upload to https://results.webkit.org, results server not online'], lines)
 
-        mock_404 = mock.patch('requests.post', new=lambda url, data: self.MockResponse(
+        mock_404 = mock.patch('requests.post', new=lambda url, headers={}, data={}: self.MockResponse(
             status_code=404,
             text=json.dumps(dict(description='No such address')),
         ))
@@ -227,15 +227,15 @@
             )],
         )
 
-        with mock.patch('requests.post', new=lambda url, data, files: self.MockResponse()):
+        with mock.patch('requests.post', new=lambda url, headers={}, data={}, files={}: self.MockResponse()):
             self.assertTrue(upload.upload_archive('https://results.webkit.org', archive='content', log_line_func=lambda _: None))
 
-        with mock.patch('requests.post', new=lambda url, data, files: self.raise_requests_ConnectionError()):
+        with mock.patch('requests.post', new=lambda url, headers={}, data={}, files={}: self.raise_requests_ConnectionError()):
             lines = []
             self.assertFalse(upload.upload_archive('https://results.webkit.org', archive='content', log_line_func=lambda line: lines.append(line)))
             self.assertEqual([' ' * 4 + 'Failed to upload test archive to https://results.webkit.org, results server not online'], lines)
 
-        mock_404 = mock.patch('requests.post', new=lambda url, data, files: self.MockResponse(
+        mock_404 = mock.patch('requests.post', new=lambda url, headers={}, data={}, files={}: self.MockResponse(
             status_code=404,
             text=json.dumps(dict(description='No such address')),
         ))