blob: 6c9afe081d8577a7be6efac821d2dff174bce417 [file] [log] [blame]
# Copyright 2017 The LUCI Authors. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.
import json
from google.protobuf import json_format
from google.protobuf import timestamp_pb2
from recipe_engine import recipe_test_api
from PB.go.chromium.org.luci.buildbucket.proto import build as build_pb2
from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb2
from PB.go.chromium.org.luci.buildbucket.proto import rpc as rpc_pb2
from . import util
class BuildbucketTestApi(recipe_test_api.RecipeTestApi):
def build(self, build_message):
"""Emulates a buildbucket build.
build_message is a buildbucket.build_pb2.Build.
"""
return self.m.properties(**{
'$recipe_engine/buildbucket': {
'build': json.loads(json_format.MessageToJson(build_message)),
},
})
def _default_git_repo(self, project): # pragma: no cover
if 'internal' in project:
return 'https://chrome-internal.googlesource.com/' + project
return 'https://chromium.googlesource.com/' + project
def ci_build_message(
self,
project='project',
bucket='ci', # shortname.
builder='builder',
git_repo=None,
git_ref='refs/heads/master',
revision='2d72510e447ab60a9728aeea2362d8be2cbd7789',
build_number=0,
build_id=8945511751514863184,
tags=None,
status=None,
):
"""Returns a typical buildbucket CI build scheduled by luci-scheduler."""
git_repo = git_repo or self._default_git_repo(project)
gitiles_host, gitiles_project = util.parse_gitiles_repo_url(git_repo)
assert gitiles_host and gitiles_project, 'invalid repo %s' % git_repo
build = build_pb2.Build(
id=build_id,
number=build_number,
tags=tags or [],
builder=build_pb2.BuilderID(
project=project,
bucket=bucket,
builder=builder,
),
created_by='user:luci-scheduler@appspot.gserviceaccount.com',
create_time=timestamp_pb2.Timestamp(seconds=1527292217),
input=build_pb2.Build.Input(
gitiles_commit=common_pb2.GitilesCommit(
host=gitiles_host,
project=gitiles_project,
ref=git_ref,
id=revision,
),
),
)
if status:
build.status = common_pb2.Status.Value(status)
return build
def ci_build(self, *args, **kwargs):
"""Returns a typical buildbucket CI build scheduled by luci-scheduler.
A shortcut for api.buildbucket.build(api.buildbucket.ci_build_message()).
Usage:
yield (api.test('basic') +
api.buildbucket.ci_build(project='my-proj', builder='win'))
"""
return self.build(self.ci_build_message(*args, **kwargs))
def try_build_message(
self,
project='project',
bucket='try', # shortname.
builder='builder',
git_repo=None,
change_number=123456,
patch_set=7,
revision=None,
build_number=0,
build_id=8945511751514863184,
tags=None,
status=None,
):
"""Emulate typical buildbucket try build scheduled by CQ.
Usage:
yield (api.test('basic') +
api.buildbucket.try_build(project='my-proj', builder='win'))
"""
git_repo = git_repo or self._default_git_repo(project)
git_host, git_project = util.parse_gitiles_repo_url(git_repo)
gerrit_host = git_host
gs_suffix = '.googlesource.com'
if gerrit_host.endswith(gs_suffix):
prefix = gerrit_host[:-len(gs_suffix)]
if not prefix.endswith('-review'):
gerrit_host = '%s-review%s' % (prefix, gs_suffix)
build = build_pb2.Build(
id=build_id,
number=build_number,
tags=tags or [],
builder=build_pb2.BuilderID(
project=project,
bucket=bucket,
builder=builder,
),
created_by='user:commit-bot@chromium.org',
create_time=timestamp_pb2.Timestamp(seconds=1527292217),
input=build_pb2.Build.Input(
gerrit_changes=[
common_pb2.GerritChange(
host=gerrit_host,
project=git_project,
change=change_number,
patchset=patch_set,
),
],
),
)
if revision:
c = build.input.gitiles_commit
c.host = git_host
c.project = git_project
c.id = revision
if status:
build.status = common_pb2.Status.Value(status)
return build
def try_build(self, *args, **kwargs):
"""Emulates a typical buildbucket try build scheduled by CQ.
Shortcut for api.buildbucket.build(api.buildbucket.try_build_message()).
Usage:
yield (api.test('basic') +
api.buildbucket.try_build(project='my-proj', builder='win'))
"""
return self.build(self.try_build_message(*args, **kwargs))
def tags(self, **tags):
"""Alias for tags in util.py. See doc there."""
return util.tags(**tags)
def simulated_buildbucket_output(
self, additional_build_parameters, step_name=None):
"""Simulates a buildbucket.get_build call."""
step_name = step_name or 'buildbucket.get'
buildbucket_output = {
'build':{
'parameters_json': json.dumps(additional_build_parameters)
}
}
return self.step_data(
step_name,
stdout=self.m.raw_io.output_text(json.dumps(buildbucket_output)))
def simulated_collect_output(self, builds, step_name=None):
"""Simulates a buildbucket.collect call."""
step_name = step_name or 'buildbucket.collect'
res = [json_format.MessageToDict(build) for build in builds]
return self.step_data(step_name, self.m.json.output(res))
def simulated_schedule_output(self, batch_response, step_name=None):
"""Simulates a buildbucket.schedule call."""
assert isinstance(batch_response, rpc_pb2.BatchResponse)
step_name = step_name or 'buildbucket.schedule'
ret_code = int(any(r.HasField('error') for r in batch_response.responses))
jsonish = json_format.MessageToDict(batch_response)
return self.step_data(
step_name, self.m.json.output_stream(jsonish, retcode=ret_code))
def simulated_search_results(self, builds, step_name=None):
"""Simulates a buildbucket.search call."""
assert isinstance(builds, list), builds
assert all(isinstance(b, build_pb2.Build) for b in builds), builds
step_name = step_name or 'buildbucket.search'
jsonish = json_format.MessageToDict(rpc_pb2.BatchResponse(
responses=[dict(search_builds=dict(builds=builds))],
))
return self.step_data(step_name, self.m.json.output_stream(jsonish))
def simulated_get(self, build, step_name=None):
"""Simulates a buildbucket.get call."""
step_name = step_name or 'buildbucket.get'
jsonish = json_format.MessageToDict(rpc_pb2.BatchResponse(
responses=[dict(get_build=build)],
))
return self.step_data(step_name, self.m.json.output_stream(jsonish))
def simulated_get_multi(self, builds, step_name=None):
"""Simulates a buildbucket.get_multi call."""
step_name = step_name or 'buildbucket.get_multi'
jsonish = json_format.MessageToDict(rpc_pb2.BatchResponse(
responses=[dict(get_build=b) for b in builds],
))
return self.step_data(step_name, self.m.json.output_stream(jsonish))