Commit 711a12e4 authored by Ben Joyce's avatar Ben Joyce Committed by Commit Bot

Add result sink for test uploads.

local runs would be ran with:
rdb stream -new -realm chromium:public ./out/Debug/bin/run_net_unittests
--result-sink-upload

Need to add --result-sink-upload to recipes. The rdb stream will be
active on the bots, as a gn.arg


Bug: 1104245,1104238
Change-Id: I8cbc9246110c28579e11c26ed92aad133a187a18
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2365216
Commit-Queue: benjamin joyce <bjoyce@chromium.org>
Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Reviewed-by: default avatarChan Li <chanli@chromium.org>
Reviewed-by: default avatarPeter Wen <wnwen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#802776}
parent 1dbea822
......@@ -46,6 +46,7 @@ python_library("test_runner_py") {
"${android_sdk_build_tools}/lib64/libc++.so",
"${android_sdk_build_tools}/split-select",
"${android_sdk_root}/platform-tools/adb",
"//third_party/requests/",
]
data_deps = [ ":devil_chromium_py" ]
if (build_with_chromium) {
......
# Copyright 2020 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 json
import os
from pylib.base import base_test_result
import requests # pylint: disable=import-error
# Maps base_test_results to the luci test-result.proto.
# https://godoc.org/go.chromium.org/luci/resultdb/proto/v1#TestStatus
RESULT_MAP = {
base_test_result.ResultType.UNKNOWN: 'STATUS_UNSPECIFIED',
base_test_result.ResultType.PASS: 'PASS',
base_test_result.ResultType.FAIL: 'FAIL',
base_test_result.ResultType.CRASH: 'CRASH',
base_test_result.ResultType.TIMEOUT: 'ABORT',
base_test_result.ResultType.SKIP: 'SKIP',
base_test_result.ResultType.NOTRUN: 'SKIP',
}
def InitResultSinkClient():
"""Initializes a result_sink_client object.
Returns a ResultSinkClient for the result_sink server. Assumes that
rdb stream is running.
"""
with open(os.environ['LUCI_CONTEXT']) as f:
sink = json.load(f)['result_sink']
return ResultSinkClient(sink)
class ResultSinkClient(object):
"""A class to store the sink's post configurations and make post requests.
This assumes that the rdb stream has been called already and that the
server is listening.
"""
def __init__(self, context):
self.url = ('http://%s/prpc/luci.resultsink.v1.Sink/ReportTestResults' %
context['address'])
self.headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'ResultSink %s' % context['auth_token'],
}
def Post(self, test_id, status):
"""Uploads the test result to the ResultSink server.
This assumes that the rdb stream has been called already and that
server is ready listening.
Args:
test_id: A string representing the test's name.
status: A string representing if the test passed, failed, etc...
Returns:
N/A
"""
assert status in RESULT_MAP
expected = status in (base_test_result.ResultType.PASS,
base_test_result.ResultType.SKIP)
status = RESULT_MAP[status]
tr = {
'testId': test_id,
'status': status,
'expected': expected,
}
requests.post(url=self.url,
headers=self.headers,
data=json.dumps({'testResults': [tr]}))
......@@ -40,6 +40,7 @@ from pylib.base import base_test_result
from pylib.base import environment_factory
from pylib.base import output_manager
from pylib.base import output_manager_factory
from pylib.base import result_sink
from pylib.base import test_instance_factory
from pylib.base import test_run_factory
from pylib.results import json_results
......@@ -218,6 +219,11 @@ def AddCommonOptions(parser):
'--isolated-script-test-repeat',
dest='repeat', type=int, default=0,
help='Number of times to repeat the specified set of tests.')
parser.add_argument('--result-sink-upload',
action='store_true',
help='Whether to upload the results to result-sink. '
'To run locally, an "rdb stream" must be active.')
# This is currently only implemented for gtests and instrumentation tests.
parser.add_argument(
'--gtest_also_run_disabled_tests', '--gtest-also-run-disabled-tests',
......@@ -733,11 +739,12 @@ _DEFAULT_PLATFORM_MODE_TESTS = [
]
def RunTestsCommand(args):
def RunTestsCommand(args, result_sink_client=None):
"""Checks test type and dispatches to the appropriate function.
Args:
args: argparse.Namespace object.
result_sink_client: A ResultSinkClient object.
Returns:
Integer indicated exit code.
......@@ -751,7 +758,7 @@ def RunTestsCommand(args):
ProcessCommonOptions(args)
logging.info('command: %s', ' '.join(sys.argv))
if args.enable_platform_mode or command in _DEFAULT_PLATFORM_MODE_TESTS:
return RunTestsInPlatformMode(args)
return RunTestsInPlatformMode(args, result_sink_client)
if command == 'python':
return _RunPythonTests(args)
......@@ -769,7 +776,7 @@ _SUPPORTED_IN_PLATFORM_MODE = [
]
def RunTestsInPlatformMode(args):
def RunTestsInPlatformMode(args, result_sink_client=None):
def infra_error(message):
logging.fatal(message)
......@@ -907,6 +914,9 @@ def RunTestsInPlatformMode(args):
iteration_count += 1
for r in iteration_results.GetAll():
if args.result_sink_upload and result_sink_client:
result_sink_client.Post(r.GetName(), r.GetType())
result_counts[r.GetName()][r.GetType()] += 1
report_results.LogFull(
results=iteration_results,
......@@ -1064,8 +1074,12 @@ def main():
args.wait_for_java_debugger)):
args.num_retries = 0
result_sink_client = None
if args.result_sink_upload:
result_sink_client = result_sink.InitResultSinkClient()
try:
return RunTestsCommand(args)
return RunTestsCommand(args, result_sink_client)
except base_error.BaseError as e:
logging.exception('Error occurred.')
if e.is_infra_error:
......
......@@ -154,6 +154,7 @@ pylib/base/environment.py
pylib/base/environment_factory.py
pylib/base/output_manager.py
pylib/base/output_manager_factory.py
pylib/base/result_sink.py
pylib/base/test_collection.py
pylib/base/test_exception.py
pylib/base/test_instance.py
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment