Bug 1698758 [wpt PR 28055] - [ci] Remove deployment of PRs to wptpr.live, a=testonly

Automatic update from web-platform-tests
[ci] Remove deployment of PRs to wptpr.live (#28055)

--

wpt-commits: 82c69ff8075f5c9b46c16a07fbbf317f555c9746
wpt-pr: 28055
This commit is contained in:
Stephen McGruer 2021-03-17 13:31:13 +00:00 committed by moz-wptsync-bot
parent e8d3eb601b
commit ab68c66a43
3 changed files with 0 additions and 1096 deletions

View File

@ -1,35 +0,0 @@
# Create previews for pull requests on https://wptpr.live
#
# Mirroring pull requests to wptpr.live requires write access to the WPT GitHub
# repository. This means that we cannot run any code from the pull request in
# doing so, to defend against attacks from malicious pull requests. As such,
# this workflow uses the 'pull_request_target' event which runs in the context
# of the base repository and thus doesn't run code from the pull request. Any
# code run in this workflow should NOT checkout or trust code from the pull
# request.
#
# Note that in pull_request_target the GITHUB token is read/write.
name: create-pr-preview
on:
pull_request_target:
types: [opened, synchronize, reopened, closed, labeled, unlabeled]
jobs:
update-pr-preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
with:
fetch-depth: 1
- name: Install dependency
run: pip install requests
- name: Deploy PR
# Use a conditional step instead of a conditional job to work around #20700.
if: github.repository == 'web-platform-tests/wpt'
run:
./tools/ci/pr_preview.py
--host https://api.github.com
--github-project web-platform-tests/wpt
--target https://wptpr.live
--timeout 600
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,378 +0,0 @@
#!/usr/bin/env python
# The service provided by this script is not critical, but it shares a GitHub
# API request quota with critical services. For this reason, all requests to
# the GitHub API are preceded by a "guard" which verifies that the subsequent
# request will not deplete the shared quota.
#
# In effect, this script will fail rather than interfere with the operation of
# critical services.
import argparse
import json
import logging
import os
import time
import requests
# The ratio of "requests remaining" to "total request quota" below which this
# script should refuse to interact with the GitHub.com API
API_RATE_LIMIT_THRESHOLD = 0.2
# The GitHub Pull Request label which indicates that a Pull Request is expected
# to be actively mirrored by the preview server
LABEL = 'safe for preview'
# The number of seconds to wait between attempts to verify that a submission
# preview is available on the Pull Request preview server
POLLING_PERIOD = 15
# Pull Requests from authors with the following associations to the project
# should automatically receive previews
#
# https://developer.github.com/v4/enum/commentauthorassociation/ (equivalent
# documentation for the REST API was not available at the time of writing)
TRUSTED_AUTHOR_ASSOCIATIONS = ('COLLABORATOR', 'MEMBER', 'OWNER')
# These GitHub accounts are not associated with individuals, and the Pull
# Requests they submit rarely require a preview.
AUTOMATION_GITHUB_USERS = (
'autofoolip', 'chromium-wpt-export-bot', 'moz-wptsync-bot',
'servo-wpt-sync'
)
DEPLOYMENT_PREFIX = 'wpt-preview-'
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def gh_request(method_name, url, body=None, media_type=None):
github_token = os.environ['GITHUB_TOKEN']
kwargs = {
'headers': {
'Authorization': 'token {}'.format(github_token),
'Accept': media_type or 'application/vnd.github.v3+json'
}
}
method = getattr(requests, method_name.lower())
if body is not None:
kwargs['json'] = body
logger.info('Issuing request: %s %s', method_name.upper(), url)
resp = method(url, **kwargs)
logger.info('Response status code: %s', resp.status_code)
# If GitHub thinks the fields are invalid, it will send a 422 back and
# include debugging information in the body. See
# https://developer.github.com/v3/#client-errors
if resp.status_code == 422:
logger.error(resp.json())
resp.raise_for_status()
if resp.status_code == 204:
return None
return resp.json()
class GitHubRateLimitException(Exception):
pass
def guard(resource):
'''Decorate a `Project` instance method which interacts with the GitHub
API, ensuring that the subsequent request will not deplete the relevant
allowance. This verification does not itself influence rate limiting:
> Accessing this endpoint does not count against your REST API rate limit.
https://developer.github.com/v3/rate_limit/
'''
def guard_decorator(func):
def wrapped(self, *args, **kwargs):
limits = gh_request('GET', '{}/rate_limit'.format(self._host))
values = limits['resources'].get(resource)
remaining = values['remaining']
limit = values['limit']
logger.info(
'Limit for "%s" resource: %s/%s', resource, remaining, limit
)
if limit and float(remaining) / limit < API_RATE_LIMIT_THRESHOLD:
raise GitHubRateLimitException(
'Exiting to avoid GitHub.com API request throttling.'
)
return func(self, *args, **kwargs)
return wrapped
return guard_decorator
class Project(object):
def __init__(self, host, github_project):
self._host = host
self._github_project = github_project
@guard('core')
def create_ref(self, refspec, revision):
url = '{}/repos/{}/git/refs'.format(self._host, self._github_project)
logger.info('Creating ref "%s" (%s)', refspec, revision)
gh_request('POST', url, {
'ref': 'refs/{}'.format(refspec),
'sha': revision
})
@guard('core')
def get_ref_revision(self, refspec):
url = '{}/repos/{}/git/refs/{}'.format(
self._host, self._github_project, refspec
)
logger.info('Fetching ref "%s"', refspec)
try:
body = gh_request('GET', url)
logger.info('Ref data: %s', json.dumps(body, indent=2))
return body['object']['sha']
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
return None
raise e
@guard('core')
def update_ref(self, refspec, revision):
url = '{}/repos/{}/git/refs/{}'.format(
self._host, self._github_project, refspec
)
logger.info('Updating ref "%s" (%s)', refspec, revision)
gh_request('PATCH', url, {'sha': revision})
@guard('core')
def delete_ref(self, refspec):
url = '{}/repos/{}/git/refs/{}'.format(
self._host, self._github_project, refspec
)
logger.info('Deleting ref "%s"', refspec)
gh_request('DELETE', url)
@guard('core')
def create_deployment(self, pull_request, revision):
url = '{}/repos/{}/deployments'.format(
self._host, self._github_project
)
# The Pull Request preview system only exposes one Deployment for a
# given Pull Request. Identifying the Deployment by the Pull Request
# number ensures that GitHub.com automatically responds to new
# Deployments by designating prior Deployments as "inactive"
environment = DEPLOYMENT_PREFIX + str(pull_request['number'])
logger.info('Creating Deployment "%s" for "%s"', environment, revision)
return gh_request('POST', url, {
'ref': revision,
'environment': environment,
'auto_merge': False,
# Pull Request previews are created regardless of GitHub Commit
# Status Checks, so Status Checks should be ignored when creating
# GitHub Deployments.
'required_contexts': []
}, 'application/vnd.github.ant-man-preview+json')
@guard('core')
def get_deployment(self, revision):
url = '{}/repos/{}/deployments?sha={}'.format(
self._host, self._github_project, revision
)
deployments = gh_request('GET', url)
return deployments.pop() if len(deployments) else None
@guard('core')
def add_deployment_status(self, target, deployment, state, description=''):
if state in ('pending', 'success'):
pr_number = deployment['environment'][len(DEPLOYMENT_PREFIX):]
environment_url = '{}/{}'.format(target, pr_number)
else:
environment_url = None
url = '{}/repos/{}/deployments/{}/statuses'.format(
self._host, self._github_project, deployment['id']
)
gh_request('POST', url, {
'state': state,
'description': description,
'environment_url': environment_url
}, 'application/vnd.github.ant-man-preview+json')
def is_open(pull_request):
return not pull_request['closed_at']
def has_mirroring_label(pull_request):
for label in pull_request['labels']:
if label['name'] == LABEL:
return True
return False
def should_be_mirrored(project, pull_request):
return (
is_open(pull_request) and (
has_mirroring_label(pull_request) or (
pull_request['user']['login'] not in AUTOMATION_GITHUB_USERS and
pull_request['author_association'] in TRUSTED_AUTHOR_ASSOCIATIONS
)
)
)
def is_deployed(host, deployment):
worktree_name = deployment['environment'][len(DEPLOYMENT_PREFIX):]
url = '{}/.git/worktrees/{}/HEAD'.format(host, worktree_name)
logger.info('Issuing request: GET %s', url)
response = requests.get(url)
logger.info('Response status code: %s', response.status_code)
if response.status_code != 200:
return False
logger.info('Response text: %s', response.text.strip())
return response.text.strip() == deployment['sha']
def update_mirror_refs(project, pull_request):
'''Update the WPT refs that control mirroring of this pull request.
Two sets of refs are used to control wptpr.live's mirroring of pull
requests:
1. refs/prs-trusted-for-preview/{number}
2. refs/prs-open/{number}
wptpr.live will only mirror a pull request if both exist for the given pull
request number; otherwise the pull request is either not open or is not
trustworthy (e.g. came from someone who doesn't have push access anyway.)
This method returns the revision that is being mirrored, or None if the
pull request should not be mirrored.
'''
refspec_trusted = 'prs-trusted-for-preview/{number}'.format(
**pull_request
)
refspec_open = 'prs-open/{number}'.format(**pull_request)
revision_latest = pull_request['head']['sha']
revision_trusted = project.get_ref_revision(refspec_trusted)
revision_open = project.get_ref_revision(refspec_open)
if should_be_mirrored(project, pull_request):
logger.info('Pull Request should be mirrored')
if revision_trusted is None:
project.create_ref(refspec_trusted, revision_latest)
elif revision_trusted != revision_latest:
project.update_ref(refspec_trusted, revision_latest)
if revision_open is None:
project.create_ref(refspec_open, revision_latest)
elif revision_open != revision_latest:
project.update_ref(refspec_open, revision_latest)
return revision_latest
logger.info('Pull Request should not be mirrored')
if not has_mirroring_label(pull_request) and revision_trusted is not None:
project.delete_ref(refspec_trusted)
if revision_open is not None and not is_open(pull_request):
project.delete_ref(refspec_open)
# No revision to be deployed to wptpr.live
return None
class DeploymentFailedException(Exception):
pass
def deploy(project, target, pull_request, revision, timeout):
'''Create a GitHub deployment for the given pull request and revision.
This method creates a pending GitHub deployment, waits for the
corresponding revision to be available on wptpr.live and marks the
deployment as successful. If the revision does not appear in the given
timeout, the deployment is marked as errored instead.'''
if project.get_deployment(revision) is not None:
return
deployment = project.create_deployment(pull_request, revision)
message = 'Waiting up to {} seconds for Deployment {} to be available on {}'.format(
timeout, deployment['environment'], target
)
logger.info(message)
project.add_deployment_status(target, deployment, 'pending', message)
start = time.time()
while not is_deployed(target, deployment):
if time.time() - start > timeout:
message = 'Deployment did not become available after {} seconds'.format(timeout)
project.add_deployment_status(target, deployment, 'error', message)
raise DeploymentFailedException(message)
time.sleep(POLLING_PERIOD)
result = project.add_deployment_status(target, deployment, 'success')
logger.info(json.dumps(result, indent=2))
def main(host, github_project, target, timeout):
project = Project(host, github_project)
with open(os.environ['GITHUB_EVENT_PATH']) as handle:
data = json.load(handle)
logger.info('Event data: %s', json.dumps(data, indent=2))
pull_request = data['pull_request']
logger.info('Processing Pull Request #%(number)d', pull_request)
revision_to_mirror = update_mirror_refs(project, pull_request)
if revision_to_mirror:
deploy(project, target, pull_request, revision_to_mirror, timeout)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='''Mirror a pull request to an externally-hosted preview
system, and create a GitHub Deployment associated with the pull
request pointing at the preview.'''
)
parser.add_argument(
'--host', required=True, help='the location of the GitHub API server'
)
parser.add_argument(
'--github-project',
required=True,
help='''the GitHub organization and GitHub project name, separated by
a forward slash (e.g. "web-platform-tests/wpt")'''
)
parser.add_argument(
'--target',
required=True,
help='''the URL of the website to which submission previews are
expected to become available'''
)
parser.add_argument(
'--timeout',
type=int,
required=True,
help='''the number of seconds to wait for a submission preview to
become available before reporting a GitHub Deployment failure'''
)
values = dict(vars(parser.parse_args()))
main(**values)

View File

@ -1,683 +0,0 @@
try:
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
except ImportError:
# Python 3 case
from http.server import BaseHTTPRequestHandler, HTTPServer
import contextlib
import errno
import json
import os
import shutil
import stat
import subprocess
import sys
import tempfile
import threading
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import pr_preview
TEST_HOST = 'localhost'
def same_members(a, b):
if len(a) != len(b):
return False
a_copy = list(a)
for elem in b:
try:
a_copy.remove(elem)
except ValueError:
return False
return len(a_copy) == 0
# When these tests are executed in Windows, files in the temporary git
# repositories may be marked as "read only" at the moment they are intended to
# be deleted. The following handler for `shutil.rmtree` accounts for this by
# making the files writable and attempting to delete them a second time.
#
# Source:
# https://stackoverflow.com/questions/1213706/what-user-do-python-scripts-run-as-in-windows
def handle_remove_readonly(func, path, exc):
excvalue = exc[1]
candidates = (os.rmdir, os.remove, os.unlink)
if func in candidates and excvalue.errno == errno.EACCES:
os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) # 0777
func(path)
else:
raise
class MockHandler(BaseHTTPRequestHandler, object):
def do_all(self):
path = self.path.split('?')[0]
request_body = None
if 'Content-Length' in self.headers:
request_body = self.rfile.read(
int(self.headers['Content-Length'])
).decode('utf-8')
if self.headers.get('Content-Type') == 'application/json':
request_body = json.loads(request_body)
for request, response in self.server.expected_traffic:
if request[0] != self.command:
continue
if request[1] != path:
continue
body_matches = True
for key in request[2]:
body_matches &= request[2][key] == request_body.get(key)
if not body_matches:
continue
break
else:
request = (self.command, path, request_body)
response = (400, {})
self.server.actual_traffic.append((request, response))
self.send_response(response[0])
self.end_headers()
if self.server.reponse_body_is_json:
self.wfile.write(json.dumps(response[1]).encode('utf-8'))
else:
self.wfile.write(response[1].encode('utf-8'))
def do_DELETE(self):
return self.do_all()
def do_GET(self):
return self.do_all()
def do_PATCH(self):
return self.do_all()
def do_POST(self):
return self.do_all()
class MockServer(HTTPServer, object):
'''HTTP server that responds to all requests with status code 200 and body
'{}' unless an alternative status code and body are specified for the given
method and path in the `responses` parameter.'''
def __init__(self, address, expected_traffic, reponse_body_is_json=True):
super(MockServer, self).__init__(address, MockHandler)
self.expected_traffic = expected_traffic
self.actual_traffic = []
self.reponse_body_is_json = reponse_body_is_json
def __enter__(self):
threading.Thread(target=lambda: self.serve_forever()).start()
return self
def __exit__(self, *args):
self.shutdown()
class Requests(object):
get_rate = ('GET', '/rate_limit', {})
ref_create_open = (
'POST', '/repos/test-org/test-repo/git/refs', {'ref':'refs/prs-open/45'}
)
ref_create_trusted = (
'POST',
'/repos/test-org/test-repo/git/refs',
{'ref':'refs/prs-trusted-for-preview/45'}
)
ref_get_open = (
'GET', '/repos/test-org/test-repo/git/refs/prs-open/45', {}
)
ref_get_trusted = (
'GET', '/repos/test-org/test-repo/git/refs/prs-trusted-for-preview/45', {}
)
ref_update_open = (
'PATCH', '/repos/test-org/test-repo/git/refs/prs-open/45', {}
)
ref_update_trusted = (
'PATCH', '/repos/test-org/test-repo/git/refs/prs-trusted-for-preview/45', {}
)
ref_delete_open = (
'DELETE', '/repos/test-org/test-repo/git/refs/prs-open/45', {}
)
ref_delete_trusted = (
'DELETE', '/repos/test-org/test-repo/git/refs/prs-trusted-for-preview/45', {}
)
deployment_get = ('GET', '/repos/test-org/test-repo/deployments', {})
deployment_create = ('POST', '/repos/test-org/test-repo/deployments', {})
deployment_status_create_pending = (
'POST',
'/repos/test-org/test-repo/deployments/24601/statuses',
{'state':'pending'}
)
deployment_status_create_error = (
'POST',
'/repos/test-org/test-repo/deployments/24601/statuses',
{'state':'error'}
)
deployment_status_create_success = (
'POST',
'/repos/test-org/test-repo/deployments/24601/statuses',
{'state':'success'}
)
preview = ('GET', '/.git/worktrees/45/HEAD', {})
class Responses(object):
no_limit = (200, {
'resources': {
'search': {
'remaining': 100,
'limit': 100
},
'core': {
'remaining': 100,
'limit': 100
}
}
})
@contextlib.contextmanager
def temp_repo():
original_dir = os.getcwd()
directory = tempfile.mkdtemp()
os.chdir(directory)
try:
subprocess.check_call(['git', 'init'], cwd=directory)
# Explicitly create the default branch.
subprocess.check_call(
['git', 'checkout', '-b', 'master'],
cwd=directory
)
subprocess.check_call(
['git', 'config', 'user.name', 'example'],
cwd=directory
)
subprocess.check_call(
['git', 'config', 'user.email', 'example@example.com'],
cwd=directory
)
subprocess.check_call(
['git', 'commit', '--allow-empty', '-m', 'first'],
cwd=directory
)
yield directory
finally:
os.chdir(original_dir)
shutil.rmtree(
directory, ignore_errors=False, onerror=handle_remove_readonly
)
def update_mirror_refs(pull_request, expected_traffic):
os.environ['GITHUB_TOKEN'] = 'c0ffee'
github_server = MockServer((TEST_HOST, 0), expected_traffic)
github_port = github_server.server_address[1]
method_threw = False
with temp_repo(), github_server:
project = pr_preview.Project(
'http://{}:{}'.format(TEST_HOST, github_port),
'test-org/test-repo',
)
try:
pr_preview.update_mirror_refs(project, pull_request)
except pr_preview.GitHubRateLimitException:
method_threw = True
return (
method_threw,
github_server.actual_traffic,
)
def deploy(pr_num, revision, expected_github_traffic, expected_preview_traffic):
os.environ['GITHUB_TOKEN'] = 'c0ffee'
github_server = MockServer((TEST_HOST, 0), expected_github_traffic)
github_port = github_server.server_address[1]
preview_server = MockServer((TEST_HOST, 0), expected_preview_traffic, reponse_body_is_json=False)
preview_port = preview_server.server_address[1]
method_threw = False
with github_server, preview_server:
project = pr_preview.Project(
'http://{}:{}'.format(TEST_HOST, github_port),
'test-org/test-repo',
)
target = 'http://{}:{}'.format(TEST_HOST, preview_port)
pull_request = {'number': pr_num}
timeout = 1
try:
pr_preview.deploy(project, target, pull_request, revision, timeout)
except (pr_preview.GitHubRateLimitException, pr_preview.DeploymentFailedException):
method_threw = True
return (
method_threw,
github_server.actual_traffic,
preview_server.actual_traffic
)
def test_update_mirror_refs_fail_rate_limited():
pull_request = {
'number': 45,
'head': {'sha': 'abc123'},
'labels': [],
'user': {'login': 'stephenmcgruer'},
'author_association': 'COLLABORATOR',
'closed_at': None,
}
expected_traffic = [
(Requests.get_rate, (
200,
{
'resources': {
'core': {
'remaining': 1,
'limit': 10
}
}
}
))
]
method_threw, actual_traffic = update_mirror_refs(
pull_request, expected_traffic
)
assert method_threw
assert same_members(expected_traffic, actual_traffic)
def test_synchronize_ignore_closed():
# No existing refs, but a closed PR event comes in. Nothing should happen.
pull_request = {
'number': 45,
'head': {'sha': 'abc123'},
'labels': [],
'user': {'login': 'stephenmcgruer'},
'author_association': 'COLLABORATOR',
'closed_at': '2019-10-28',
}
expected_traffic = [
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_trusted, (404, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_open, (404, {})),
]
method_threw, actual_traffic = update_mirror_refs(
pull_request, expected_traffic
)
assert not method_threw
assert same_members(expected_traffic, actual_traffic)
def test_update_mirror_refs_collaborator():
pull_request = {
'number': 45,
'head': {'sha': 'abc123'},
'labels': [],
'user': {'login': 'stephenmcgruer'},
'author_association': 'COLLABORATOR',
'closed_at': None,
}
expected_traffic = [
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_trusted, (404, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_open, (404, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_create_open, (200, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_create_trusted, (200, {})),
]
method_threw, actual_traffic, = update_mirror_refs(
pull_request, expected_traffic
)
assert not method_threw
assert same_members(expected_traffic, actual_traffic)
def test_update_mirror_refs_ignore_collaborator_bot():
pull_request = {
'number': 45,
'head': {'sha': 'abc123'},
'labels': [],
'user': {'login': 'chromium-wpt-export-bot'},
'author_association': 'COLLABORATOR',
'closed_at': None,
}
expected_traffic = [
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_trusted, (404, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_open, (404, {})),
]
method_threw, actual_traffic = update_mirror_refs(
pull_request, expected_traffic
)
assert not method_threw
assert same_members(expected_traffic, actual_traffic)
def test_update_mirror_refs_ignore_untrusted_contributor():
pull_request = {
'number': 45,
'head': {'sha': 'abc123'},
'labels': [],
'user': {'login': 'stephenmcgruer'},
'author_association': 'CONTRIBUTOR',
'closed_at': None,
}
expected_traffic = [
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_trusted, (404, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_open, (404, {})),
]
method_threw, actual_traffic = update_mirror_refs(
pull_request, expected_traffic
)
assert not method_threw
assert same_members(expected_traffic, actual_traffic)
def test_update_mirror_refs_trusted_contributor():
pull_request = {
'number': 45,
'head': {'sha': 'abc123'},
# user here is a contributor (untrusted), but the issue
# has been labelled as safe.
'labels': [{'name': 'safe for preview'}],
'user': {'login': 'Hexcles'},
'author_association': 'CONTRIBUTOR',
'closed_at': None,
}
expected_traffic = [
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_trusted, (404, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_open, (404, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_create_open, (200, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_create_trusted, (200, {})),
]
method_threw, actual_traffic = update_mirror_refs(
pull_request, expected_traffic
)
assert not method_threw
assert same_members(expected_traffic, actual_traffic)
def test_synchronize_sync_bot_with_label():
pull_request = {
'number': 45,
'head': {'sha': 'abc123'},
# user here is a bot which is normally not mirrored,
# but the issue has been labelled as safe.
'labels': [{'name': 'safe for preview'}],
'user': {'login': 'chromium-wpt-export-bot'},
'author_association': 'COLLABORATOR',
'closed_at': None,
}
expected_traffic = [
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_trusted, (404, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_open, (404, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_create_open, (200, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_create_trusted, (200, {})),
]
method_threw, actual_traffic = update_mirror_refs(
pull_request, expected_traffic
)
assert not method_threw
assert same_members(expected_traffic, actual_traffic)
def test_update_mirror_refs_update_collaborator():
pull_request = {
'number': 45,
'head': {'sha': 'abc123'},
'labels': [],
'user': {'login': 'stephenmcgruer'},
'author_association': 'COLLABORATOR',
'closed_at': None,
}
expected_traffic = [
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_trusted, (
200,
{
'object': {'sha': 'def234'},
}
)),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_open, (
200,
{
'object': {'sha': 'def234'},
}
)),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_update_open, (200, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_update_trusted, (200, {})),
]
method_threw, actual_traffic = update_mirror_refs(
pull_request, expected_traffic
)
assert not method_threw
assert same_members(expected_traffic, actual_traffic)
def test_synchronize_update_member():
pull_request = {
'number': 45,
'head': {'sha': 'abc123'},
'labels': [],
'user': {'login': 'jgraham'},
'author_association': 'MEMBER',
'closed_at': None,
}
expected_traffic = [
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_trusted, (
200,
{
'object': {'sha': 'def234'},
}
)),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_open, (
200,
{
'object': {'sha': 'def234'},
}
)),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_update_open, (200, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_update_trusted, (200, {}))
]
method_threw, actual_traffic = update_mirror_refs(
pull_request, expected_traffic
)
assert not method_threw
assert same_members(expected_traffic, actual_traffic)
def test_update_mirror_refs_delete_collaborator():
pull_request = {
'number': 45,
'head': {'sha': 'abc123'},
'labels': [],
'user': {'login': 'stephenmcgruer'},
'author_association': 'COLLABORATOR',
'closed_at': 2019-10-30,
}
expected_traffic = [
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_trusted, (
200,
{
'object': {'sha': 'def234'},
}
)),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_get_open, (
200,
{
'object': {'sha': 'def234'},
}
)),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_delete_trusted, (204, None)),
(Requests.get_rate, Responses.no_limit),
(Requests.ref_delete_open, (204, None)),
]
method_threw, actual_traffic = update_mirror_refs(
pull_request, expected_traffic
)
assert not method_threw
assert same_members(expected_traffic, actual_traffic)
def test_deploy_fail_rate_limited():
expected_github_traffic = [
(Requests.get_rate, (
200,
{
'resources': {
'core': {
'remaining': 1,
'limit': 10
}
}
}
))
]
expected_preview_traffic = []
pr_num = 45
revision = "abcdef123"
method_threw, actual_github_traffic, actual_preview_traffic = deploy(
pr_num, revision, expected_github_traffic, expected_preview_traffic
)
assert method_threw
assert actual_github_traffic == expected_github_traffic
assert actual_preview_traffic == expected_preview_traffic
def test_deploy_success():
pr_num = 45
revision = 'abcdef123'
expected_github_traffic = [
(Requests.get_rate, Responses.no_limit),
(Requests.deployment_get, (200, [])),
(Requests.get_rate, Responses.no_limit),
(Requests.deployment_create, (200, {
'id': 24601,
'sha': revision,
'environment': 'wpt-preview-45',
})),
(Requests.get_rate, Responses.no_limit),
(Requests.deployment_status_create_pending, (200, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.deployment_status_create_success, (200, {}))
]
expected_preview_traffic = [
(Requests.preview, (200, revision))
]
method_threw, actual_github_traffic, actual_preview_traffic = deploy(
pr_num, revision, expected_github_traffic, expected_preview_traffic
)
assert not method_threw
assert actual_github_traffic == expected_github_traffic
assert actual_preview_traffic == expected_preview_traffic
def test_deploy_timeout_missing():
pr_num = 45
revision = 'abcdef123'
expected_github_traffic = [
(Requests.get_rate, Responses.no_limit),
(Requests.deployment_get, (200, [])),
(Requests.get_rate, Responses.no_limit),
(Requests.deployment_create, (200, {
'id': 24601,
'sha': revision,
'environment': 'wpt-preview-45',
})),
(Requests.get_rate, Responses.no_limit),
(Requests.deployment_status_create_pending, (200, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.deployment_status_create_error, (200, {}))
]
expected_preview_traffic = [
(Requests.preview, (404, ""))
]
method_threw, actual_github_traffic, actual_preview_traffic = deploy(
pr_num, revision, expected_github_traffic, expected_preview_traffic
)
assert method_threw
assert expected_github_traffic == actual_github_traffic
ping_count = len(actual_preview_traffic)
assert ping_count > 0
assert actual_preview_traffic == expected_preview_traffic * ping_count
def test_deploy_timeout_wrong_revision():
pr_num = 45
revision = 'abcdef123'
expected_github_traffic = [
(Requests.get_rate, Responses.no_limit),
(Requests.deployment_get, (200, [])),
(Requests.get_rate, Responses.no_limit),
(Requests.deployment_create, (200, {
'id': 24601,
'sha': revision,
'environment': 'wpt-preview-45',
})),
(Requests.get_rate, Responses.no_limit),
(Requests.deployment_status_create_pending, (200, {})),
(Requests.get_rate, Responses.no_limit),
(Requests.deployment_status_create_error, (200, {}))
]
expected_preview_traffic = [
# wptpr.live has the wrong revision deployed
(Requests.preview, (200, 'ghijkl456'))
]
method_threw, actual_github_traffic, actual_preview_traffic = deploy(
pr_num, revision, expected_github_traffic, expected_preview_traffic
)
assert method_threw
assert expected_github_traffic == actual_github_traffic
ping_count = len(actual_preview_traffic)
assert ping_count > 0
assert actual_preview_traffic == expected_preview_traffic * ping_count