1 // Copyright (C) 2012 Google Inc. All rights reserved.
2 // Copyright (C) 2012 Zan Dobersek <zandobersek@gmail.com>
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 var loader = loader || {};
34 var TEST_RESULTS_SERVER = 'http://test-results.appspot.com/';
36 function pathToBuilderResultsFile(builderName) {
37 return TEST_RESULTS_SERVER + 'testfile?builder=' + builderName +
38 '&master=' + builders.master(builderName).name +
39 '&testtype=' + g_history.crossDashboardState.testType + '&name=';
42 loader.request = function(url, success, error, opt_isBinaryData)
44 var xhr = new XMLHttpRequest();
45 xhr.open('GET', url, true);
47 xhr.overrideMimeType('text/plain; charset=x-user-defined');
48 xhr.onreadystatechange = function(e) {
49 if (xhr.readyState == 4) {
50 if (xhr.status == 200)
59 loader.Loader = function()
61 this._loadingSteps = [
62 this._loadBuildersList,
63 this._loadResultsFiles,
66 this._buildersThatFailedToLoad = [];
67 this._staleBuilders = [];
68 this._errors = new ui.Errors();
69 // TODO(jparent): Pass in the appropriate history obj per db.
70 this._history = g_history;
73 // TODO(aboxhall): figure out whether this is a performance bottleneck and
74 // change calling code to understand the trie structure instead if necessary.
75 loader.Loader._flattenTrie = function(trie, prefix)
78 for (var name in trie) {
79 var fullName = prefix ? prefix + "/" + name : name;
80 var data = trie[name];
81 if ("results" in data)
82 result[fullName] = data;
84 var partialResult = loader.Loader._flattenTrie(data, fullName);
85 for (var key in partialResult) {
86 result[key] = partialResult[key];
93 loader.Loader.prototype = {
98 showErrors: function()
102 buildersThatFailedToLoad: function() {
103 return this._buildersThatFailedToLoad;
105 staleBuilders: function() {
106 return this._staleBuilders;
108 _loadNext: function()
110 var loadingStep = this._loadingSteps.shift();
113 this._history.initialize();
116 loadingStep.apply(this);
118 _loadBuildersList: function()
120 builders.loadBuildersList(currentBuilderGroupName(), this._history.crossDashboardState.testType);
123 _loadResultsFiles: function()
125 var builderNames = Object.keys(currentBuilders());
126 if (builderNames.length)
127 builderNames.forEach(this._loadResultsFileForBuilder.bind(this));
132 _loadResultsFileForBuilder: function(builderName)
135 // FIXME: times_ms.json should store the actual buildnumber and
136 // this should be changed to buildnumber=latest, which doesn't work.
137 if (history.isTreeMap())
138 resultsFilename = 'times_ms.json&buildnumber=0';
139 else if (this._history.crossDashboardState.showAllRuns)
140 resultsFilename = 'results.json';
142 resultsFilename = 'results-small.json';
144 var resultsFileLocation = pathToBuilderResultsFile(builderName) + resultsFilename;
145 loader.request(resultsFileLocation,
146 partial(function(loader, builderName, xhr) {
147 loader._handleResultsFileLoaded(builderName, xhr.responseText);
148 }, this, builderName),
149 partial(function(loader, builderName, xhr) {
150 loader._handleResultsFileLoadError(builderName);
151 }, this, builderName));
153 _handleResultsFileLoaded: function(builderName, fileData)
155 if (history.isTreeMap())
156 this._processTimesJSONData(builderName, fileData);
158 this._processResultsJSONData(builderName, fileData);
160 // We need this work-around for webkit.org/b/50589.
161 if (!g_resultsByBuilder[builderName]) {
162 this._handleResultsFileLoadError(builderName);
166 this._handleResourceLoad();
168 _processTimesJSONData: function(builderName, fileData)
170 // FIXME: We should probably include the builderName in the JSON
171 // rather than relying on only loading one JSON file per page.
172 g_resultsByBuilder[builderName] = JSON.parse(fileData);
174 _processResultsJSONData: function(builderName, fileData)
176 var builds = JSON.parse(fileData);
178 if (builderName == 'version' || builderName == 'failure_map')
181 var ONE_DAY_SECONDS = 60 * 60 * 24;
182 var ONE_WEEK_SECONDS = ONE_DAY_SECONDS * 7;
184 // If a test suite stops being run on a given builder, we don't want to show it.
185 // Assume any builder without a run in two weeks for a given test suite isn't
186 // running that suite anymore.
187 // FIXME: Grab which bots run which tests directly from the buildbot JSON instead.
188 var lastRunSeconds = builds[builderName].secondsSinceEpoch[0];
189 if ((Date.now() / 1000) - lastRunSeconds > ONE_WEEK_SECONDS)
192 if ((Date.now() / 1000) - lastRunSeconds > ONE_DAY_SECONDS)
193 this._staleBuilders.push(builderName);
195 builds[builderName][results.TESTS] = loader.Loader._flattenTrie(builds[builderName][results.TESTS]);
196 g_resultsByBuilder[builderName] = builds[builderName];
198 _handleResultsFileLoadError: function(builderName)
200 // FIXME: loader shouldn't depend on state defined in dashboard_base.js.
201 this._buildersThatFailedToLoad.push(builderName);
203 // Remove this builder from builders, so we don't try to use the
204 // data that isn't there.
205 delete currentBuilders()[builderName];
207 // Proceed as if the resource had loaded.
208 this._handleResourceLoad();
210 _handleResourceLoad: function()
212 if (this._haveResultsFilesLoaded())
215 _haveResultsFilesLoaded: function()
217 for (var builderName in currentBuilders()) {
218 if (!g_resultsByBuilder[builderName] && this._buildersThatFailedToLoad.indexOf(builderName) < 0)
223 _addErrors: function()
225 if (this._buildersThatFailedToLoad.length)
226 this._errors.addError('ERROR: Failed to get data from ' + this._buildersThatFailedToLoad.toString() +'.');
228 if (this._staleBuilders.length)
229 this._errors.addError('ERROR: Data from ' + this._staleBuilders.toString() + ' is more than 1 day stale.');