1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Uploads the results to the flakiness dashboard server."""
6 # pylint: disable=E1002,R0201
15 from pylib
import cmd_helper
16 from pylib
import constants
17 from pylib
.results
.flakiness_dashboard
import json_results_generator
18 from pylib
.utils
import repo_utils
22 class JSONResultsGenerator(json_results_generator
.JSONResultsGeneratorBase
):
23 """Writes test results to a JSON file and handles uploading that file to
24 the test results server.
26 def __init__(self
, builder_name
, build_name
, build_number
, tmp_folder
,
27 test_results_map
, test_results_server
, test_type
, master_name
):
28 super(JSONResultsGenerator
, self
).__init
__(
29 builder_name
=builder_name
,
30 build_name
=build_name
,
31 build_number
=build_number
,
32 results_file_base_path
=tmp_folder
,
33 builder_base_url
=None,
34 test_results_map
=test_results_map
,
35 svn_repositories
=(('webkit', 'third_party/WebKit'),
37 test_results_server
=test_results_server
,
39 master_name
=master_name
)
42 def _GetModifierChar(self
, test_name
):
43 if test_name
not in self
._test
_results
_map
:
44 return self
.__class
__.NO_DATA_RESULT
46 return self
._test
_results
_map
[test_name
].modifier
49 def _GetSVNRevision(self
, in_directory
):
50 """Returns the git/svn revision for the given directory.
53 in_directory: The directory relative to src.
55 def _is_git_directory(in_directory
):
56 """Returns true if the given directory is in a git repository.
59 in_directory: The directory path to be tested.
61 if os
.path
.exists(os
.path
.join(in_directory
, '.git')):
63 parent
= os
.path
.dirname(in_directory
)
64 if parent
== constants
.DIR_SOURCE_ROOT
or parent
== in_directory
:
66 return _is_git_directory(parent
)
68 in_directory
= os
.path
.join(constants
.DIR_SOURCE_ROOT
, in_directory
)
70 if not os
.path
.exists(os
.path
.join(in_directory
, '.svn')):
71 if _is_git_directory(in_directory
):
72 return repo_utils
.GetGitHeadSHA1(in_directory
)
76 output
= cmd_helper
.GetCmdOutput(['svn', 'info', '--xml'], cwd
=in_directory
)
78 dom
= xml
.dom
.minidom
.parseString(output
)
79 return dom
.getElementsByTagName('entry')[0].getAttribute('revision')
80 except xml
.parsers
.expat
.ExpatError
:
85 class ResultsUploader(object):
86 """Handles uploading buildbot tests results to the flakiness dashboard."""
87 def __init__(self
, tests_type
):
88 self
._build
_number
= os
.environ
.get('BUILDBOT_BUILDNUMBER')
89 self
._builder
_name
= os
.environ
.get('BUILDBOT_BUILDERNAME')
90 self
._tests
_type
= tests_type
92 if not self
._build
_number
or not self
._builder
_name
:
93 raise Exception('You should not be uploading tests results to the server'
94 'from your local machine.')
96 upstream
= (tests_type
!= 'Chromium_Android_Instrumentation')
98 # TODO(frankf): Use factory properties (see buildbot/bb_device_steps.py)
99 # This requires passing the actual master name (e.g. 'ChromiumFYI' not
101 from slave
import slave_utils
# pylint: disable=F0401
102 self
._build
_name
= slave_utils
.SlaveBuildName(constants
.DIR_SOURCE_ROOT
)
103 self
._master
_name
= slave_utils
.GetActiveMaster()
105 self
._build
_name
= 'chromium-android'
106 buildbot_branch
= os
.environ
.get('BUILDBOT_BRANCH')
107 if not buildbot_branch
:
108 buildbot_branch
= 'master'
109 self
._master
_name
= '%s-%s' % (self
._build
_name
, buildbot_branch
)
111 self
._test
_results
_map
= {}
113 def AddResults(self
, test_results
):
114 # TODO(frankf): Differentiate between fail/crash/timeouts.
116 (test_results
.GetPass(), False,
117 json_results_generator
.JSONResultsGeneratorBase
.PASS_RESULT
),
118 (test_results
.GetFail(), True,
119 json_results_generator
.JSONResultsGeneratorBase
.FAIL_RESULT
),
120 (test_results
.GetCrash(), True,
121 json_results_generator
.JSONResultsGeneratorBase
.FAIL_RESULT
),
122 (test_results
.GetTimeout(), True,
123 json_results_generator
.JSONResultsGeneratorBase
.FAIL_RESULT
),
124 (test_results
.GetUnknown(), True,
125 json_results_generator
.JSONResultsGeneratorBase
.NO_DATA_RESULT
),
128 for results_list
, failed
, modifier
in conversion_map
:
129 for single_test_result
in results_list
:
130 test_result
= json_results_generator
.TestResult(
131 test
=single_test_result
.GetName(),
133 elapsed_time
=single_test_result
.GetDuration() / 1000)
134 # The WebKit TestResult object sets the modifier it based on test name.
135 # Since we don't use the same test naming convention as WebKit the
136 # modifier will be wrong, so we need to overwrite it.
137 test_result
.modifier
= modifier
139 self
._test
_results
_map
[single_test_result
.GetName()] = test_result
141 def Upload(self
, test_results_server
):
142 if not self
._test
_results
_map
:
145 tmp_folder
= tempfile
.mkdtemp()
148 results_generator
= JSONResultsGenerator(
149 builder_name
=self
._builder
_name
,
150 build_name
=self
._build
_name
,
151 build_number
=self
._build
_number
,
152 tmp_folder
=tmp_folder
,
153 test_results_map
=self
._test
_results
_map
,
154 test_results_server
=test_results_server
,
155 test_type
=self
._tests
_type
,
156 master_name
=self
._master
_name
)
158 json_files
= ["incremental_results.json", "times_ms.json"]
159 results_generator
.GenerateJSONOutput()
160 results_generator
.GenerateTimesMSFile()
161 results_generator
.UploadJSONFiles(json_files
)
162 except Exception as e
:
163 logging
.error("Uploading results to test server failed: %s." % e
)
165 shutil
.rmtree(tmp_folder
)
168 def Upload(results
, flakiness_dashboard_server
, test_type
):
169 """Reports test results to the flakiness dashboard for Chrome for Android.
172 results: test results.
173 flakiness_dashboard_server: the server to upload the results to.
174 test_type: the type of the tests (as displayed by the flakiness dashboard).
176 uploader
= ResultsUploader(test_type
)
177 uploader
.AddResults(results
)
178 uploader
.Upload(flakiness_dashboard_server
)