2a85ce3985bc0b627b6238b3ddaa896b14f477ab
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Tools / GardeningServer / scripts / model.js
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 var model = model || {};
27
28 (function () {
29
30 var kCommitLogLength = 50;
31
32 model.state = {};
33 model.state.failureAnalysisByTest = {};
34 model.state.rebaselineQueue = [];
35 model.state.expectationsUpdateQueue = [];
36
37 function findAndMarkRevertedRevisions(commitDataList)
38 {
39     var revertedRevisions = {};
40     $.each(commitDataList, function(index, commitData) {
41         if (commitData.revertedRevision)
42             revertedRevisions[commitData.revertedRevision] = true;
43     });
44     $.each(commitDataList, function(index, commitData) {
45         if (commitData.revision in revertedRevisions)
46             commitData.wasReverted = true;
47     });
48 }
49
50 function fuzzyFind(testName, commitData)
51 {
52     var indexOfLastDot = testName.lastIndexOf('.');
53     var stem = indexOfLastDot == -1 ? testName : testName.substr(0, indexOfLastDot);
54     return commitData.message.indexOf(stem) != -1;
55 }
56
57 function heuristicallyNarrowRegressionRange(failureAnalysis)
58 {
59     var commitDataList = model.state.recentCommits;
60     var commitDataIndex = commitDataList.length - 1;
61
62     for(var revision = failureAnalysis.newestPassingRevision + 1; revision <= failureAnalysis.oldestFailingRevision; ++revision) {
63         while (commitDataIndex >= 0 && commitDataList[commitDataIndex].revision < revision)
64             --commitDataIndex;
65         var commitData = commitDataList[commitDataIndex];
66         if (commitData.revision != revision)
67             continue;
68         if (fuzzyFind(failureAnalysis.testName, commitData)) {
69             failureAnalysis.oldestFailingRevision = revision;
70             failureAnalysis.newestPassingRevision = revision - 1;
71             return;
72         }
73     }
74 }
75
76 model.queueForRebaseline = function(failureInfo)
77 {
78     model.state.rebaselineQueue.push(failureInfo);
79 };
80
81 model.takeRebaselineQueue = function()
82 {
83     var queue = model.state.rebaselineQueue;
84     model.state.rebaselineQueue = [];
85     return queue;
86 };
87
88 model.queueForExpectationUpdate = function(failureInfo)
89 {
90     model.state.expectationsUpdateQueue.push(failureInfo);
91 };
92
93 model.takeExpectationUpdateQueue = function()
94 {
95     var queue = model.state.expectationsUpdateQueue;
96     model.state.expectationsUpdateQueue = [];
97     return queue;
98 };
99
100 var g_commitIndex = {};
101
102 model.updateRecentCommits = function(callback)
103 {
104     trac.recentCommitData('trunk', kCommitLogLength, function(commitDataList) {
105         model.state.recentCommits = commitDataList;
106         updateCommitIndex();
107         findAndMarkRevertedRevisions(model.state.recentCommits);
108         callback();
109     });
110 };
111
112 function updateCommitIndex()
113 {
114     model.state.recentCommits.forEach(function(commitData) {
115         g_commitIndex[commitData.revision] = commitData;
116     });
117 }
118
119 model.commitDataListForRevisionRange = function(fromRevision, toRevision)
120 {
121     var result = [];
122     for (var revision = fromRevision; revision <= toRevision; ++revision) {
123         var commitData = g_commitIndex[revision];
124         if (commitData)
125             result.push(commitData);
126     }
127     return result;
128 };
129
130 model.buildersInFlightForRevision = function(revision)
131 {
132     var builders = {};
133     Object.keys(model.state.resultsByBuilder).forEach(function(builderName) {
134         var results = model.state.resultsByBuilder[builderName];
135         if (parseInt(results.blink_revision) < revision)
136             builders[builderName] = { actual: 'BUILDING' };
137     });
138     return builders;
139 };
140
141 model.latestRevision = function()
142 {
143     return model.state.recentCommits[0].revision;
144 }
145
146 model.latestRevisionWithNoBuildersInFlight = function()
147 {
148     var revision = 0;
149     Object.keys(model.state.resultsByBuilder).forEach(function(builderName) {
150         var results = model.state.resultsByBuilder[builderName];
151         if (!results.blink_revision)
152             return;
153         var testedRevision = parseInt(results.blink_revision);
154         revision = revision ? Math.min(revision, testedRevision) : testedRevision;
155     });
156     return revision;
157 }
158
159 model.latestRevisionByBuilder = function()
160 {
161     var revision = {};
162     Object.keys(model.state.resultsByBuilder).forEach(function(builderName) {
163         revision[builderName] = model.state.resultsByBuilder[builderName].blink_revision;
164     });
165     return revision;
166 }
167
168 model.updateResultsByBuilder = function(callback)
169 {
170     results.fetchResultsByBuilder(Object.keys(config.builders), function(resultsByBuilder) {
171         model.state.resultsByBuilder = resultsByBuilder;
172         callback();
173     });
174 };
175
176 model.analyzeUnexpectedFailures = function(callback, completionCallback)
177 {
178     var unexpectedFailures = results.unexpectedFailuresByTest(model.state.resultsByBuilder);
179
180     $.each(model.state.failureAnalysisByTest, function(testName, failureAnalysis) {
181         if (!(testName in unexpectedFailures))
182             delete model.state.failureAnalysisByTest[testName];
183     });
184
185     var tracker = new base.RequestTracker(Object.keys(unexpectedFailures).length, completionCallback);
186     $.each(unexpectedFailures, function(testName, resultNodesByBuilder) {
187         var builderNameList = Object.keys(resultNodesByBuilder);
188         results.unifyRegressionRanges(builderNameList, testName, function(oldestFailingRevision, newestPassingRevision) {
189             var failureAnalysis = {
190                 'testName': testName,
191                 'resultNodesByBuilder': resultNodesByBuilder,
192                 'oldestFailingRevision': oldestFailingRevision,
193                 'newestPassingRevision': newestPassingRevision,
194             };
195
196             heuristicallyNarrowRegressionRange(failureAnalysis);
197
198             var previousFailureAnalysis = model.state.failureAnalysisByTest[testName];
199             if (previousFailureAnalysis
200                 && previousFailureAnalysis.oldestFailingRevision <= failureAnalysis.oldestFailingRevision
201                 && previousFailureAnalysis.newestPassingRevision >= failureAnalysis.newestPassingRevision) {
202                 failureAnalysis.oldestFailingRevision = previousFailureAnalysis.oldestFailingRevision;
203                 failureAnalysis.newestPassingRevision = previousFailureAnalysis.newestPassingRevision;
204             }
205
206             model.state.failureAnalysisByTest[testName] = failureAnalysis;
207             
208             callback(failureAnalysis);
209             tracker.requestComplete();
210         });
211     });
212 };
213
214 model.unexpectedFailureInfoForTestName = function(testName)
215 {
216     var resultsByTest = results.unexpectedFailuresByTest(model.state.resultsByBuilder);
217
218     return Object.keys(resultsByTest[testName]).map(function(builderName) {
219         return results.failureInfoForTestAndBuilder(resultsByTest, testName, builderName);
220     });
221 };
222
223 model.analyzeexpectedFailures = function(callback)
224 {
225     var expectedFailures = results.expectedFailuresByTest(model.state.resultsByBuilder);
226     $.each(expectedFailures, function(testName, resultNodesByBuilder) {
227         var failureAnalysis = {
228             'testName': testName,
229             'resultNodesByBuilder': resultNodesByBuilder,
230         };
231
232         // FIXME: Consider looking at the history to see how long this test
233         // has been failing.
234
235         callback(failureAnalysis);
236     });
237 };
238
239 })();