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
26var results = results || {};
27
28(function() {
29
30var PASS = 'PASS';
31var TIMEOUT = 'TIMEOUT';
32var TEXT = 'TEXT';
33var CRASH = 'CRASH';
34var LEAK = 'LEAK';
35var IMAGE = 'IMAGE';
36var IMAGE_TEXT = 'IMAGE+TEXT';
37var AUDIO = 'AUDIO';
38var MISSING = 'MISSING';
39
40var kFailingResults = [TEXT, IMAGE_TEXT, AUDIO];
41
42var kExpectedImageSuffix = '-expected.png';
43var kActualImageSuffix = '-actual.png';
44var kImageDiffSuffix = '-diff.png';
45var kExpectedAudioSuffix = '-expected.wav';
46var kActualAudioSuffix = '-actual.wav';
47var kExpectedTextSuffix = '-expected.txt';
48var kActualTextSuffix = '-actual.txt';
49var kDiffTextSuffix = '-diff.txt';
50var kCrashLogSuffix = '-crash-log.txt';
51var kLeakLogSuffix = '-leak-log.txt';
52
53var kPreferredSuffixOrder = [
54    kExpectedImageSuffix,
55    kActualImageSuffix,
56    kImageDiffSuffix,
57    kExpectedTextSuffix,
58    kActualTextSuffix,
59    kDiffTextSuffix,
60    kCrashLogSuffix,
61    kExpectedAudioSuffix,
62    kActualAudioSuffix,
63    kLeakLogSuffix,
64];
65
66// Kinds of results.
67results.kActualKind = 'actual';
68results.kExpectedKind = 'expected';
69results.kDiffKind = 'diff';
70results.kUnknownKind = 'unknown';
71
72// Types of tests.
73results.kImageType = 'image';
74results.kAudioType = 'audio';
75results.kTextType = 'text';
76
77function possibleSuffixListFor(failureTypeList)
78{
79    var suffixList = [];
80
81    function pushImageSuffixes()
82    {
83        suffixList.push(kExpectedImageSuffix);
84        suffixList.push(kActualImageSuffix);
85        suffixList.push(kImageDiffSuffix);
86    }
87
88    function pushAudioSuffixes()
89    {
90        suffixList.push(kExpectedAudioSuffix);
91        suffixList.push(kActualAudioSuffix);
92    }
93
94    function pushTextSuffixes()
95    {
96        suffixList.push(kActualTextSuffix);
97        suffixList.push(kExpectedTextSuffix);
98        suffixList.push(kDiffTextSuffix);
99    }
100
101    failureTypeList.forEach(function(failureType) {
102        switch(failureType) {
103        case IMAGE:
104            pushImageSuffixes();
105            break;
106        case TEXT:
107            pushTextSuffixes();
108            break;
109        case AUDIO:
110            pushAudioSuffixes();
111            break;
112        case IMAGE_TEXT:
113            pushImageSuffixes();
114            pushTextSuffixes();
115            break;
116        case CRASH:
117            suffixList.push(kCrashLogSuffix);
118            break;
119        case LEAK:
120            suffixList.push(kLeakLogSuffix);
121            break;
122        case MISSING:
123            pushImageSuffixes();
124            pushTextSuffixes();
125            break;
126        default:
127            // FIXME: Add support for the rest of the result types.
128            // '-expected.html',
129            // '-expected-mismatch.html',
130            // ... and possibly more.
131            break;
132        }
133    });
134
135    return suffixList.unique();
136}
137
138function failureTypeList(failureBlob)
139{
140    return failureBlob.split(' ');
141};
142
143function resultsDirectoryURL(builderName)
144{
145    return 'https://storage.googleapis.com/chromium-layout-test-archives/' +
146        builderName.replace(/[ .()]/g, '_') + '/results/layout-test-results/';
147}
148
149results.failureInfo = function(testName, builderName, result)
150{
151    return {
152        'testName': testName,
153        'builderName': builderName,
154        'failureTypeList': failureTypeList(result),
155    };
156}
157
158results.resultKind = function(url)
159{
160    if (/-actual\.[a-z]+$/.test(url))
161        return results.kActualKind;
162    else if (/-expected\.[a-z]+$/.test(url))
163        return results.kExpectedKind;
164    else if (/diff\.[a-z]+$/.test(url))
165        return results.kDiffKind;
166    return results.kUnknownKind;
167}
168
169results.resultType = function(url)
170{
171    if (/\.png$/.test(url))
172        return results.kImageType;
173    if (/\.wav$/.test(url))
174        return results.kAudioType;
175    return results.kTextType;
176}
177
178function sortResultURLsBySuffix(urls)
179{
180    var sortedURLs = [];
181    kPreferredSuffixOrder.forEach(function(suffix) {
182        urls.forEach(function(url) {
183            if (!url.endsWith(suffix))
184                return;
185            sortedURLs.push(url);
186        });
187    });
188    if (sortedURLs.length != urls.length)
189        throw "sortResultURLsBySuffix failed to return the same number of URLs.";
190    return sortedURLs;
191}
192
193results._trimExtension = function(url)
194{
195    var index = url.lastIndexOf('.');
196    if (index == -1)
197        return url;
198    return url.substr(0, index);
199}
200
201results.fetchResultsURLs = function(failureInfo)
202{
203    var testNameStem = results._trimExtension(failureInfo.testName);
204    var urlStem = resultsDirectoryURL(failureInfo.builderName);
205
206    var suffixList = possibleSuffixListFor(failureInfo.failureTypeList);
207    var resultURLs = [];
208    var probePromises = [];
209    suffixList.forEach(function(suffix) {
210        var url = urlStem + testNameStem + suffix;
211        probePromises.push(net.probe(url).then(
212            function() {
213                resultURLs.push(url);
214            },
215            function() {}));
216    });
217    return Promise.all(probePromises).then(function() {
218        return sortResultURLsBySuffix(resultURLs);
219    });
220};
221
222})();
223