initial import
[vuplus_webkit] / Tools / BuildSlaveSupport / build.webkit.org-config / public_html / TestFailures / 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     model.state.recentCommits.forEach(function(commitData) {
114         g_commitIndex[commitData.revision] = commitData;
115     });
116 }
117
118 model.commitDataListForRevisionRange = function(fromRevision, toRevision)
119 {
120     var result = [];
121     for (var revision = fromRevision; revision <= toRevision; ++revision) {
122         var commitData = g_commitIndex[revision];
123         if (commitData)
124             result.push(commitData);
125     }
126     return result;
127 };
128
129 model.buildersInFlightForRevision = function(revision)
130 {
131     var builders = {};
132     Object.keys(model.state.resultsByBuilder).forEach(function(builderName) {
133         var results = model.state.resultsByBuilder[builderName];
134         if (parseInt(results.revision) < revision)
135             builders[builderName] = { actual: 'BUILDING' };
136     });
137     return builders;
138 };
139
140 model.updateResultsByBuilder = function(callback)
141 {
142     results.fetchResultsByBuilder(Object.keys(config.kBuilders), function(resultsByBuilder) {
143         model.state.resultsByBuilder = resultsByBuilder;
144         callback();
145     });
146 };
147
148 model.analyzeUnexpectedFailures = function(callback, completionCallback)
149 {
150     var unexpectedFailures = results.unexpectedFailuresByTest(model.state.resultsByBuilder);
151
152     $.each(model.state.failureAnalysisByTest, function(testName, failureAnalysis) {
153         if (!(testName in unexpectedFailures))
154             delete model.state.failureAnalysisByTest[testName];
155     });
156
157     var tracker = new base.RequestTracker(Object.keys(unexpectedFailures).length, completionCallback);
158     $.each(unexpectedFailures, function(testName, resultNodesByBuilder) {
159         var builderNameList = Object.keys(resultNodesByBuilder);
160         results.unifyRegressionRanges(builderNameList, testName, function(oldestFailingRevision, newestPassingRevision) {
161             var failureAnalysis = {
162                 'testName': testName,
163                 'resultNodesByBuilder': resultNodesByBuilder,
164                 'oldestFailingRevision': oldestFailingRevision,
165                 'newestPassingRevision': newestPassingRevision,
166             };
167
168             heuristicallyNarrowRegressionRange(failureAnalysis);
169
170             var previousFailureAnalysis = model.state.failureAnalysisByTest[testName];
171             if (previousFailureAnalysis
172                 && previousFailureAnalysis.oldestFailingRevision <= failureAnalysis.oldestFailingRevision
173                 && previousFailureAnalysis.newestPassingRevision >= failureAnalysis.newestPassingRevision) {
174                 failureAnalysis.oldestFailingRevision = previousFailureAnalysis.oldestFailingRevision;
175                 failureAnalysis.newestPassingRevision = previousFailureAnalysis.newestPassingRevision;
176             }
177
178             model.state.failureAnalysisByTest[testName] = failureAnalysis;
179             callback(failureAnalysis);
180             tracker.requestComplete();
181         });
182     });
183 };
184
185 model.unexpectedFailureInfoForTestName = function(testName)
186 {
187     var resultsByTest = results.unexpectedFailuresByTest(model.state.resultsByBuilder);
188
189     return Object.keys(resultsByTest[testName]).map(function(builderName) {
190         return results.failureInfoForTestAndBuilder(resultsByTest, testName, builderName);
191     });
192 };
193
194 model.analyzeUnexpectedSuccesses = function(callback)
195 {
196     var unexpectedSuccesses = results.unexpectedSuccessesByTest(model.state.resultsByBuilder);
197     $.each(unexpectedSuccesses, function(testName, resultNodesByBuilder) {
198         var successAnalysis = {
199             'testName': testName,
200             'resultNodesByBuilder': resultNodesByBuilder,
201         };
202
203         // FIXME: Consider looking at the history to see how long this test
204         // has been unexpectedly passing.
205
206         callback(successAnalysis);
207     });
208 };
209
210 model.analyzeExpectedOrUnexpectedFailures = function(callback)
211 {
212     var expectedFailures = results.expectedOrUnexpectedFailuresByTest(model.state.resultsByBuilder);
213     $.each(expectedFailures, function(testName, resultNodesByBuilder) {
214         var failureAnalysis = {
215             'testName': testName,
216             'resultNodesByBuilder': resultNodesByBuilder,
217         };
218
219         // FIXME: Consider looking at the history to see how long this test
220         // has been failing.
221
222         callback(failureAnalysis);
223     });
224 };
225
226 })();