Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Tools / GardeningServer / model / ct-failures.html
1 <!--
2 Copyright 2014 The Chromium Authors. All rights reserved.
3 Use of this source code is governed by a BSD-style license that can be
4 found in the LICENSE file.
5 -->
6
7 <link rel="import" href="../lib/net.html">
8 <link rel="import" href="../lib/update-util.html">
9 <link rel="import" href="ct-builder-failure.html">
10 <link rel="import" href="ct-step-failure.html">
11 <link rel="import" href="ct-failure-group.html">
12 <link rel="import" href="ct-builder-failure-group-data.html">
13 <link rel="import" href="ct-step-failure-group-data.html">
14 <link rel="import" href="ct-trooper-failure-group-data.html">
15 <link rel="import" href="ct-commit-list.html">
16
17 <script>
18 function CTFailures(commitLog) {
19   this.commitLog = commitLog;
20   // Maps a tree id to an array of CTFailureGroups within that tree.
21   this.failures = null;
22   this.lastUpdateDate = null;
23 }
24
25 (function() {
26 'use strict';
27
28 // FIXME: This could potentially move onto CTStepFailureGroupData as it isn't relevant to
29 // trooper failures.
30 // Reverse sorting order, if a > b, return a negative number.
31 CTFailures.prototype._failureByTreeListComparator = function(tree, a, b) {
32   if (tree === undefined)
33     tree = 'chromium';
34
35   var rev_a = a.data.commitList.revisions;
36   var rev_b = b.data.commitList.revisions;
37
38   if (!rev_a || !Object.keys(rev_a).length) {
39     if (!rev_b || !Object.keys(rev_b).length)
40       return 0;
41     return 1;
42   } else if (!rev_b || !Object.keys(rev_b).length) {
43     return -1;
44   }
45
46   // Prioritize the tree's revision, if they are unequal (else, fallback below)
47   if (rev_a[tree] && rev_b[tree] &&
48       rev_a[tree].last() != rev_b[tree].last()) {
49     return rev_b[tree].last() - rev_a[tree].last();
50   }
51
52   // Compare other revisions in alphabetical order.
53   var keys = Object.keys(rev_a).sort();
54   for (var i = 0; i < keys.length; i++) {
55     if (keys[i] == tree)  // Already taken care of, above.
56       continue;
57
58     var a_list = rev_a[keys[i]];
59     var b_list = rev_b[keys[i]];
60     if (!b_list)
61       return -1;
62
63     if (a_list.last() != b_list.last())
64       return b_list.last() - a_list.last();
65   }
66   return 0;
67 };
68
69 // Updates the format of the alerts array to be easier to parse.
70 CTFailures.prototype._mungeAlerts = function(alerts) {
71   alerts.forEach(function(failure) {
72     // FIXME: Have the server store the actual failure type in a different
73     // field instead of smashing it into the reason.
74     if (failure.failureType) {
75       // The server has been fixed.
76     } else {
77       if (failure.reason) {
78         var parts = failure.reason.split(':');
79         failure.reason = parts[0];
80         failure.failureType = parts[1] || 'FAIL';
81       } else {
82         failure.failureType = 'UNKNOWN';
83       }
84     }
85   });
86 };
87
88 CTFailures.prototype.update = function() {
89   var annotationPromise = CTFailureGroup.fetchAnnotations();
90   return Promise.all([annotationPromise, net.json('https://sheriff-o-matic.appspot.com/alerts'),
91       net.json('https://trooper-o-matic.appspot.com/alerts')]).then(function(data_array) {
92     var annotations = data_array[0];
93     var sheriff_data = data_array[1];
94     var trooper_data = data_array[2];
95
96     var newFailures = {};
97     this.lastUpdateDate = new Date(sheriff_data.date * 1000);
98     this._mungeAlerts(sheriff_data.alerts);
99     // FIXME: Change builder_alerts to expose the alerts as a map instead of an array.
100     var alertsByKey = {}
101     sheriff_data.alerts.forEach(function(alert) {
102       alertsByKey[alert.key] = alert;
103     });
104     // Update |failures| with the appropriate CTFailureGroup's for each
105     // tree.
106     sheriff_data.range_groups.forEach(function(rangeGroup) {
107       this._processFailuresForRangeGroup(newFailures, rangeGroup, alertsByKey, annotations);
108     }.bind(this));
109
110     // Sort failure groups so that newer failures are shown at the top
111     // of the UI.
112     Object.keys(newFailures, function (tree, failuresByTree) {
113       failuresByTree.sort(this._failureByTreeListComparator.bind(this, tree));
114     }.bind(this));
115
116     sheriff_data.stale_builder_alerts.forEach(function(alert) {
117       this._processBuilderFailure(newFailures, alert);
118     }.bind(this));
119
120     this.failures = updateUtil.updateLeft(this.failures, newFailures);
121     this._processTrooperFailures(trooper_data);
122   }.bind(this));
123 };
124
125 CTFailures.prototype._failureComparator = function(a, b) {
126   if (a.step > b.step)
127     return 1;
128   if (a.step < b.step)
129     return -1
130   if (a.testName > b.testName)
131     return 1;
132   if (a.testName < b.testName)
133     return -1
134   return 0;
135 };
136
137 CTFailures.prototype._processTrooperFailures = function(data) {
138   var trooper_failures = [];
139   Object.keys(data, function(failureType, failuresByTree) {
140     Object.keys(failuresByTree, function(tree, failure) {
141       if (failure.should_alert) {
142         trooper_failures.push(new CTFailureGroup('',
143             new CTTrooperFailureGroupData(failure.details, failure.url, failure, failureType, tree)));
144       }
145     });
146   });
147   this.failures['trooper'] = trooper_failures;
148 };
149
150 CTFailures.prototype._groupFailuresByTreeAndReason = function(failures, annotations) {
151   var failuresByTree = {};
152   failures.forEach(function(failure) {
153     // Establish the key to uniquely identify a failure by reason.
154     var failureKey = CTStepFailure.createKey(failure);
155
156     var reasonKey = JSON.stringify({
157       step: failure.step_name,
158       reason: failure.reason,
159     });
160
161     // FIXME: Use a model class instead of a dumb object.
162     if (!failuresByTree[failure.tree])
163       failuresByTree[failure.tree] = {};
164     if (!failuresByTree[failure.tree][reasonKey])
165       failuresByTree[failure.tree][reasonKey] = {};
166     failuresByTree[failure.tree][reasonKey][failure.builder_name] = {
167       key: failureKey,
168       // FIXME: Rename to failureType.
169       actual: failure.failureType,
170       lastFailingBuild: failure.last_failing_build,
171       earliestFailingBuild: failure.failing_build,
172       masterUrl: failure.master_url,
173       failingBuildCount: (1 + failure.last_failing_build - failure.failing_build),
174       annotation: annotations[failureKey],
175     };
176   });
177   return failuresByTree
178 };
179
180 CTFailures.prototype._processFailuresForRangeGroup = function(newFailures, rangeGroup, alerts, annotations) {
181   // A rangeGroup may be related to multiple alerts (via |failure_keys|). Categorize
182   // these failures by reason (cause of failure), so that they can be grouped in the UI
183   // (via a CTFailureGroup).
184   var failures = rangeGroup.failure_keys.map(function(failure_key) {
185     return alerts[failure_key];
186   });
187   var failuresByTree = this._groupFailuresByTreeAndReason(failures, annotations);
188
189   if (Object.isEmpty(failuresByTree))
190     return;
191
192   Object.keys(failuresByTree, function(tree, resultsByReason) {
193     var treeFailures = [];
194     Object.keys(resultsByReason, function(reasonKey, resultsByBuilder) {
195       var failure = JSON.parse(reasonKey);
196       treeFailures.push(
197           new CTStepFailure(failure.step, failure.reason, resultsByBuilder));
198     })
199     treeFailures.sort(this._failureComparator);
200
201     if (!newFailures[tree])
202       newFailures[tree] = [];
203     var commitList = new CTCommitList(this.commitLog, rangeGroup.likely_revisions);
204     newFailures[tree].push(new CTFailureGroup(rangeGroup.sort_key, new CTStepFailureGroupData(treeFailures, commitList)));
205   }.bind(this));
206 };
207
208 CTFailures.prototype._processBuilderFailure = function(newFailures, alert) {
209   var timeSinceLastUpdate = (this.lastUpdateDate.valueOf() / 1000) - alert.last_update_time;
210   var failure = new CTBuilderFailure(alert.tree, alert.master_url, alert.builder_name, alert.state,
211       timeSinceLastUpdate, alert.pending_builds);
212   var data = new CTBuilderFailureGroupData(failure, alert.builder_name,
213       alert.master_url + "/builders/" + alert.builder_name);
214   if (!newFailures[alert.tree])
215     newFailures[alert.tree] = [];
216   newFailures[alert.tree].push(new CTFailureGroup(failure.key, data, 'builders'));
217 };
218
219 })();
220
221 </script>