Upstream version 10.38.222.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Tools / TestResultServer / static-dashboards / loader.js
1 // Copyright (C) 2012 Google Inc. All rights reserved.
2 // Copyright (C) 2012 Zan Dobersek <zandobersek@gmail.com>
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
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
13 // distribution.
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.
17 //
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.
29
30 var loader = loader || {};
31
32 (function() {
33
34 var TEST_RESULTS_SERVER = 'http://test-results.appspot.com/';
35
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=';
40 }
41
42 loader.request = function(url, success, error, opt_isBinaryData)
43 {
44     var xhr = new XMLHttpRequest();
45     xhr.open('GET', url, true);
46     if (opt_isBinaryData)
47         xhr.overrideMimeType('text/plain; charset=x-user-defined');
48     xhr.onreadystatechange = function(e) {
49         if (xhr.readyState == 4) {
50             if (xhr.status == 200)
51                 success(xhr);
52             else
53                 error(xhr);
54         }
55     }
56     xhr.send();
57 }
58
59 loader.Loader = function()
60 {
61     this._loadingSteps = [
62         this._loadBuildersList,
63         this._loadResultsFiles,
64     ];
65
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;
71 }
72
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)
76 {
77     var result = {};
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;
83         else {
84             var partialResult = loader.Loader._flattenTrie(data, fullName);
85             for (var key in partialResult) {
86                 result[key] = partialResult[key];
87             }
88         }
89     }
90     return result;
91 }
92
93 loader.Loader.prototype = {
94     load: function()
95     {
96         this._loadNext();
97     },
98     showErrors: function()
99     {
100         this._errors.show();
101     },
102     buildersThatFailedToLoad: function() {
103         return this._buildersThatFailedToLoad;
104     },
105     staleBuilders: function() {
106         return this._staleBuilders;
107     },
108     _loadNext: function()
109     {
110         var loadingStep = this._loadingSteps.shift();
111         if (!loadingStep) {
112             this._addErrors();
113             this._history.initialize();
114             return;
115         }
116         loadingStep.apply(this);
117     },
118     _loadBuildersList: function()
119     {
120         builders.loadBuildersList(currentBuilderGroupName(), this._history.crossDashboardState.testType);
121         this._loadNext();
122     },
123     _loadResultsFiles: function()
124     {
125         var builderNames = Object.keys(currentBuilders());
126         if (builderNames.length)
127             builderNames.forEach(this._loadResultsFileForBuilder.bind(this));
128         else
129             this._loadNext();
130
131     },
132     _loadResultsFileForBuilder: function(builderName)
133     {
134         var resultsFilename;
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';
141         else
142             resultsFilename = 'results-small.json';
143
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));
152     },
153     _handleResultsFileLoaded: function(builderName, fileData)
154     {
155         if (history.isTreeMap())
156             this._processTimesJSONData(builderName, fileData);
157         else
158             this._processResultsJSONData(builderName, fileData);
159
160         // We need this work-around for webkit.org/b/50589.
161         if (!g_resultsByBuilder[builderName]) {
162             this._handleResultsFileLoadError(builderName);
163             return;
164         }
165
166         this._handleResourceLoad();
167     },
168     _processTimesJSONData: function(builderName, fileData)
169     {
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);
173     },
174     _processResultsJSONData: function(builderName, fileData)
175     {
176         var builds = JSON.parse(fileData);
177
178         if (builderName == 'version' || builderName == 'failure_map')
179              return;
180
181         var ONE_DAY_SECONDS = 60 * 60 * 24;
182         var ONE_WEEK_SECONDS = ONE_DAY_SECONDS * 7;
183
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)
190             return;
191
192         if ((Date.now() / 1000) - lastRunSeconds > ONE_DAY_SECONDS)
193             this._staleBuilders.push(builderName);
194
195         builds[builderName][results.TESTS] = loader.Loader._flattenTrie(builds[builderName][results.TESTS]);
196         g_resultsByBuilder[builderName] = builds[builderName];
197     },
198     _handleResultsFileLoadError: function(builderName)
199     {
200         // FIXME: loader shouldn't depend on state defined in dashboard_base.js.
201         this._buildersThatFailedToLoad.push(builderName);
202
203         // Remove this builder from builders, so we don't try to use the
204         // data that isn't there.
205         delete currentBuilders()[builderName];
206
207         // Proceed as if the resource had loaded.
208         this._handleResourceLoad();
209     },
210     _handleResourceLoad: function()
211     {
212         if (this._haveResultsFilesLoaded())
213             this._loadNext();
214     },
215     _haveResultsFilesLoaded: function()
216     {
217         for (var builderName in currentBuilders()) {
218             if (!g_resultsByBuilder[builderName] && this._buildersThatFailedToLoad.indexOf(builderName) < 0)
219                 return false;
220         }
221         return true;
222     },
223     _addErrors: function()
224     {
225         if (this._buildersThatFailedToLoad.length)
226             this._errors.addError('ERROR: Failed to get data from ' + this._buildersThatFailedToLoad.toString() +'.');
227
228         if (this._staleBuilders.length)
229             this._errors.addError('ERROR: Data from ' + this._staleBuilders.toString() + ' is more than 1 day stale.');
230     }
231 }
232
233 })();