blob: 54986c1069e995f9b547f6f09ed65aee86e5f741 [file]
# Copyright 2016 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
from common.findit_http_client import FinditHttpClient
from libs.test_results import test_results_util
from services import ci_failure
from services import step_util
from services import swarmed_test_util
from services import swarming
from waterfall import buildbot
def _GetMatchingWaterfallBuildStep(cq_build_step, http_client):
"""Returns the matching Waterfall build step of the given CQ one.
Args:
cq_build_step (BuildStep): A build step on Commit Queue.
http_client (RetryHttpClient): A http client to send http requests.
Returns:
(master_name, builder_name, build_number, step_name, step_metadata)
or
None
"""
no_matching_result = (None, None, None, None, None)
# 0. Get step_metadata.
step_metadata = cq_build_step.step_metadata or ci_failure.GetStepMetadata(
cq_build_step.master_name, cq_build_step.builder_name,
cq_build_step.build_number, cq_build_step.step_name)
if not step_metadata:
logging.error('Couldn\'t get step_metadata')
return no_matching_result
# 1. Map a cq trybot to the matching waterfall buildbot:
# get master_name and builder_name.
wf_master_name = step_metadata.get('waterfall_mastername')
wf_builder_name = step_metadata.get('waterfall_buildername')
if not wf_master_name or not wf_builder_name:
# Either waterfall_mastername or waterfall_buildername doesn't exist.
logging.info('%s/%s has no matching Waterfall buildbot',
cq_build_step.master_name, cq_build_step.builder_name)
return no_matching_result # No matching Waterfall buildbot.
# 2. Get "name" of the CQ trybot step.
# Name of the step in the tags of a Swarming task.
# Can't use step name, as cq one is with "(with patch)" while waterfall one
# without.
name = step_metadata.get('canonical_step_name')
# The OS in which the test runs on. The same test binary might run on two
# different OS platforms.
os_name = step_metadata.get('dimensions', {}).get('os')
if not name or not os_name:
logging.error('Couldn\'t find name/os')
return no_matching_result # No name of the step.
# TODO: cache and throttle QPS to the same master.
# 3. Retrieve latest completed build cycle on the buildbot.
builds = buildbot.GetRecentCompletedBuilds(wf_master_name, wf_builder_name,
http_client)
if not builds:
logging.error('Couldn\'t find latest builds.')
return no_matching_result # No name of the step.
# 4. Check whether there is matching step.
tasks = swarming.ListSwarmingTasksDataByTags(
http_client,
wf_master_name,
wf_builder_name,
builds[0],
additional_tag_filters={
'name': name,
'os': os_name
})
if tasks: # One matching buildbot is found.
wf_step_name = tasks[0].tags['stepname'][0] if 'stepname' in tasks[
0].tags else ''
logging.info('%s/%s/%s is mapped to %s/%s/%s', cq_build_step.master_name,
cq_build_step.builder_name, cq_build_step.step_name,
wf_master_name, wf_builder_name, wf_step_name)
return (wf_master_name, wf_builder_name, builds[0], wf_step_name,
step_metadata)
return no_matching_result
def FindMatchingWaterfallStep(build_step, test_name):
"""Finds the matching Waterfall step and checks whether it is supported.
Only Swarmed and gtest-based steps are supported at the moment.
Args:
build_step (BuildStep): A build step on Waterfall or Commit Queue. It
will be updated with the matching Waterfall step and whether it is
Swarmed and supported.
test_name (str): The name of the test.
"""
build_step.swarmed = False
build_step.supported = False
http_client = FinditHttpClient()
if build_step.on_cq:
wf_master_name, wf_builder_name, wf_build_number, wf_step_name, metadata = (
_GetMatchingWaterfallBuildStep(build_step, http_client))
build_step.wf_master_name = wf_master_name
build_step.wf_builder_name = wf_builder_name
build_step.wf_build_number = wf_build_number
build_step.wf_step_name = wf_step_name
if not build_step.has_matching_waterfall_step:
return
else:
build_step.wf_master_name = build_step.master_name
build_step.wf_builder_name = build_step.builder_name
build_step.wf_build_number = build_step.build_number
build_step.wf_step_name = build_step.step_name
metadata = build_step.step_metadata or ci_failure.GetStepMetadata(
build_step.master_name, build_step.builder_name,
build_step.build_number, build_step.step_name)
if not metadata:
logging.error('Couldn\'t get step_metadata')
return
build_step.step_metadata = metadata
# Query Swarming for isolated data.
build_step.swarmed = True if metadata.get('swarm_task_ids') else False
if build_step.swarmed:
need_to_continue = False
for task_id in metadata['swarm_task_ids']:
output = swarmed_test_util.GetTestResultForSwarmingTask(
task_id, http_client)
if output:
# Guess from the format.
test_result_object = test_results_util.GetTestResultObject(
output, partial_result=True)
if not test_result_object:
build_step.supported = False
elif not step_util.IsStepSupportedByFindit(
test_result_object,
metadata.get('canonical_step_name') or build_step.step_name,
build_step.wf_master_name):
build_step.supported = False
else:
test_exists = test_result_object.DoesTestExist(test_name)
if test_exists:
build_step.supported = True
elif test_result_object.contains_all_tests:
# There is no such test for sure.
build_step.supported = False
else:
# Test is not in this task, but cannot determine if it's in other
# tasks.
need_to_continue = True
if not need_to_continue:
break