| OLD | NEW |
| (Empty) |
| 1 #!/bin/env/python | |
| 2 # Copyright (c) 2006-2009 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 import os | |
| 7 import zipfile | |
| 8 | |
| 9 from failure_finder import FailureFinder | |
| 10 | |
| 11 TEST_BUILDER_OUTPUT = """090723 10:38:22 test_shell_thread.py:289 | |
| 12 ERROR chrome/fast/forms/textarea-metrics.html failed: | |
| 13 Text diff mismatch | |
| 14 090723 10:38:21 test_shell_thread.py:289 | |
| 15 ERROR chrome/fast/dom/xss-DENIED-javascript-variations.html failed: | |
| 16 Text diff mismatch | |
| 17 090723 10:37:58 test_shell_thread.py:289 | |
| 18 ERROR LayoutTests/plugins/bindings-test.html failed: | |
| 19 Text diff mismatch | |
| 20 | |
| 21 ------------------------------------------------------------------------------ | |
| 22 Expected to crash, but passed (1): | |
| 23 chrome/fast/forms/textarea-metrics.html | |
| 24 | |
| 25 Regressions: Unexpected failures (2): | |
| 26 chrome/fast/dom/xss-DENIED-javascript-variations.html = FAIL | |
| 27 LayoutTests/plugins/bindings-test.html = FAIL | |
| 28 ------------------------------------------------------------------------------ | |
| 29 """ | |
| 30 | |
| 31 TEST_FAILURE_1 = ("layout-test-results/chrome/fast/forms/" | |
| 32 "textarea-metrics-actual.txt") | |
| 33 TEST_FAILURE_2 = ("layout-test-results/chrome/fast/dom/" | |
| 34 "xss-DENIED-javascript-variations-actual.txt") | |
| 35 TEST_FAILURE_3 = ("layout-test-results/LayoutTests/plugins/" | |
| 36 "bindings-test-actual.txt") | |
| 37 | |
| 38 TEST_ARCHIVE_OUTPUT = """ | |
| 39 Adding layout-test-results\pending\fast\repaint\not-real-actual.checksum | |
| 40 Adding layout-test-results\pending\fast\repaint\not-real-actual.png | |
| 41 Adding layout-test-results\pending\fast\repaint\not-real-actual.txt | |
| 42 last change: 22057 | |
| 43 build name: webkit-rel | |
| 44 host name: codf138 | |
| 45 saving results to \\my\test\location\webkit-rel\22057 | |
| 46 program finished with exit code 0 | |
| 47 """ | |
| 48 | |
| 49 TEST_TEST_EXPECTATIONS = """ | |
| 50 BUG1234 chrome/fast/forms/textarea-metrics.html = CRASH | |
| 51 """ | |
| 52 | |
| 53 TEST_BUILDER_LOG_FILE = "TEST_builder.log" | |
| 54 TEST_ARCHIVE_LOG_FILE = "TEST_archive.log" | |
| 55 TEST_DUMMY_ZIP_FILE = "TEST_zipfile.zip" | |
| 56 TEST_EXPECTATIONS_FILE = "TEST_expectations.txt" | |
| 57 | |
| 58 WEBKIT_BUILDER_NUMBER = "9800" | |
| 59 WEBKIT_FAILURES = ( | |
| 60 ["LayoutTests/fast/backgrounds/animated-svg-as-mask.html", | |
| 61 "LayoutTests/fast/backgrounds/background-clip-text.html", | |
| 62 "LayoutTests/fast/backgrounds/mask-composite.html", | |
| 63 "LayoutTests/fast/backgrounds/repeat/mask-negative-offset-repeat.html", | |
| 64 "LayoutTests/fast/backgrounds/svg-as-background-3.html", | |
| 65 "LayoutTests/fast/backgrounds/svg-as-background-6.html", | |
| 66 "LayoutTests/fast/backgrounds/svg-as-mask.html", | |
| 67 "LayoutTests/fast/block/float/013.html", | |
| 68 "LayoutTests/fast/block/float/nested-clearance.html", | |
| 69 "LayoutTests/fast/block/positioning/047.html"]) | |
| 70 | |
| 71 CHROMIUM_BASELINE = "chrome/fast/forms/basic-buttons.html" | |
| 72 EXPECTED_CHROMIUM_LOCAL_BASELINE = "./chrome/fast/forms/basic-buttons.html" | |
| 73 EXPECTED_CHROMIUM_URL_BASELINE = ("http://src.chromium.org/viewvc/chrome/" | |
| 74 "trunk/src/webkit/data/layout_tests/chrome/" | |
| 75 "fast/forms/basic-buttons.html") | |
| 76 | |
| 77 WEBKIT_BASELINE = "LayoutTests/fast/forms/11423.html" | |
| 78 EXPECTED_WEBKIT_LOCAL_BASELINE = "./LayoutTests/fast/forms/11423.html" | |
| 79 EXPECTED_WEBKIT_URL_BASELINE = ( | |
| 80 "http://svn.webkit.org/repository/webkit/trunk/" | |
| 81 "LayoutTests/fast/forms/11423.html") | |
| 82 | |
| 83 TEST_ZIP_FILE = ("http://build.chromium.org/buildbot/layout_test_results/" | |
| 84 "webkit-rel/21432/layout-test-results.zip") | |
| 85 | |
| 86 EXPECTED_REVISION = "20861" | |
| 87 EXPECTED_BUILD_NAME = "webkit-rel" | |
| 88 | |
| 89 SVG_TEST_EXPECTATION = ( | |
| 90 "LayoutTests/svg/custom/foreign-object-skew-expected.png") | |
| 91 SVG_TEST_EXPECTATION_UPSTREAM = ("LayoutTests/svg/custom/" | |
| 92 "foreign-object-skew-expected-upstream.png") | |
| 93 WEBARCHIVE_TEST_EXPECTATION = ("LayoutTests/webarchive/adopt-attribute-" | |
| 94 "styled-body-webarchive-expected.webarchive") | |
| 95 DOM_TEST_EXPECTATION = ("LayoutTests/fast/dom/" | |
| 96 "attribute-downcast-right-expected.txt") | |
| 97 DOM_TEST_EXPECTATION_UPSTREAM = ("LayoutTests/fast/dom/" | |
| 98 "attribute-downcast-right-" | |
| 99 "expected-upstream.png") | |
| 100 | |
| 101 TEST_EXPECTATIONS = """ | |
| 102 BUG1234 WONTFIX : LayoutTests/fast/backgrounds/svg-as-background-3.html = FAIL | |
| 103 BUG3456 WIN : LayoutTests/fast/backgrounds/svg-as-background-6.html = CRASH | |
| 104 BUG4567 : LayoutTests/fast/backgrounds/svg-as-mask.html = PASS | |
| 105 WONTFIX : LayoutTests/fast/block/ = FAIL | |
| 106 """ | |
| 107 | |
| 108 EXPECT_EXACT_MATCH = "LayoutTests/fast/backgrounds/svg-as-background-6.html" | |
| 109 EXPECT_GENERAL_MATCH = "LayoutTests/fast/block/float/013.html" | |
| 110 EXPECT_NO_MATCH = "LayoutTests/fast/backgrounds/svg-as-background-99.html" | |
| 111 | |
| 112 WEBKIT_ORG = "webkit.org" | |
| 113 CHROMIUM_ORG = "chromium.org" | |
| 114 | |
| 115 | |
| 116 class FailureFinderTest(object): | |
| 117 | |
| 118 def runTests(self): | |
| 119 all_tests_passed = True | |
| 120 | |
| 121 tests = ["testWhitespaceInBuilderName", | |
| 122 "testGetLastBuild", | |
| 123 "testFindMatchesInBuilderOutput", | |
| 124 "testScrapeBuilderOutput", | |
| 125 "testGetChromiumBaseline", | |
| 126 "testGetWebkitBaseline", | |
| 127 "testZipDownload", | |
| 128 "testUseLocalOutput", | |
| 129 "testTranslateBuildToZip", | |
| 130 "testGetBaseline", | |
| 131 "testFindTestExpectations", | |
| 132 "testFull"] | |
| 133 | |
| 134 for test in tests: | |
| 135 try: | |
| 136 result = eval(test + "()") | |
| 137 if result: | |
| 138 print "[ OK ] %s" % test | |
| 139 else: | |
| 140 all_tests_passed = False | |
| 141 print "[ FAIL ] %s" % test | |
| 142 except: | |
| 143 print "[ ERROR ] %s" % test | |
| 144 return all_tests_passed | |
| 145 | |
| 146 | |
| 147 def _getBasicFailureFinder(): | |
| 148 return FailureFinder(None, "Webkit", False, "", ".", 10, False) | |
| 149 | |
| 150 | |
| 151 def _testLastBuild(failure_finder): | |
| 152 try: | |
| 153 last_build = failure_finder.GetLastBuild() | |
| 154 # Verify that last_build is not empty and is a number. | |
| 155 build = int(last_build) | |
| 156 return (build > 0) | |
| 157 except: | |
| 158 return False | |
| 159 | |
| 160 | |
| 161 def testGetLastBuild(): | |
| 162 test = _getBasicFailureFinder() | |
| 163 return _testLastBuild(test) | |
| 164 | |
| 165 | |
| 166 def testWhitespaceInBuilderName(): | |
| 167 test = _getBasicFailureFinder() | |
| 168 test.SetPlatform("Webkit (webkit.org)") | |
| 169 return _testLastBuild(test) | |
| 170 | |
| 171 | |
| 172 def testScrapeBuilderOutput(): | |
| 173 | |
| 174 # Try on the default builder. | |
| 175 test = _getBasicFailureFinder() | |
| 176 test.build = "9800" | |
| 177 output = test._ScrapeBuilderOutput() | |
| 178 if not output: | |
| 179 return False | |
| 180 | |
| 181 # Try on a crazy builder on the FYI waterfall. | |
| 182 test = _getBasicFailureFinder() | |
| 183 test.build = "1766" | |
| 184 test.SetPlatform("Webkit Linux (webkit.org)") | |
| 185 output = test._ScrapeBuilderOutput() | |
| 186 if not output: | |
| 187 return False | |
| 188 | |
| 189 return True | |
| 190 | |
| 191 | |
| 192 def testFindMatchesInBuilderOutput(): | |
| 193 test = _getBasicFailureFinder() | |
| 194 test.exclude_known_failures = True | |
| 195 matches = test._FindMatchesInBuilderOutput(TEST_BUILDER_OUTPUT) | |
| 196 # Verify that we found x matches. | |
| 197 if len(matches) != 2: | |
| 198 print "Did not find all unexpected failures." | |
| 199 return False | |
| 200 | |
| 201 test.exclude_known_failures = False | |
| 202 matches = test._FindMatchesInBuilderOutput(TEST_BUILDER_OUTPUT) | |
| 203 if len(matches) != 3: | |
| 204 print "Did not find all failures." | |
| 205 return False | |
| 206 return True | |
| 207 | |
| 208 | |
| 209 def _testBaseline(test_name, expected_local, expected_url): | |
| 210 test = _getBasicFailureFinder() | |
| 211 # Test baseline that is obviously in Chromium's tree. | |
| 212 baseline = test._GetBaseline(test_name, ".", False) | |
| 213 try: | |
| 214 os.remove(baseline.local_file) | |
| 215 if (baseline.local_file != expected_local or | |
| 216 baseline.baseline_url != expected_url): | |
| 217 return False | |
| 218 except: | |
| 219 return False | |
| 220 return True | |
| 221 | |
| 222 | |
| 223 def testGetChromiumBaseline(): | |
| 224 return _testBaseline(CHROMIUM_BASELINE, EXPECTED_CHROMIUM_LOCAL_BASELINE, | |
| 225 EXPECTED_CHROMIUM_URL_BASELINE) | |
| 226 | |
| 227 | |
| 228 def testGetWebkitBaseline(): | |
| 229 return _testBaseline(WEBKIT_BASELINE, EXPECTED_WEBKIT_LOCAL_BASELINE, | |
| 230 EXPECTED_WEBKIT_URL_BASELINE) | |
| 231 | |
| 232 | |
| 233 def testUseLocalOutput(): | |
| 234 test_result = True | |
| 235 try: | |
| 236 _writeFile(TEST_BUILDER_LOG_FILE, TEST_BUILDER_OUTPUT) | |
| 237 _writeFile(TEST_ARCHIVE_LOG_FILE, TEST_ARCHIVE_OUTPUT) | |
| 238 _writeFile(TEST_EXPECTATIONS_FILE, TEST_TEST_EXPECTATIONS) | |
| 239 zip = zipfile.ZipFile(TEST_DUMMY_ZIP_FILE, 'w') | |
| 240 zip.write(TEST_BUILDER_LOG_FILE, TEST_FAILURE_1) | |
| 241 zip.write(TEST_BUILDER_LOG_FILE, TEST_FAILURE_2) | |
| 242 zip.write(TEST_BUILDER_LOG_FILE, TEST_FAILURE_3) | |
| 243 zip.close() | |
| 244 test = _getBasicFailureFinder() | |
| 245 test.archive_step_log_file = TEST_ARCHIVE_LOG_FILE | |
| 246 test.builder_output_log_file = TEST_BUILDER_LOG_FILE | |
| 247 test.test_expectations_file = TEST_EXPECTATIONS_FILE | |
| 248 test.zip_file = TEST_DUMMY_ZIP_FILE | |
| 249 test.dont_download = True | |
| 250 test.exclude_known_failures = True | |
| 251 test.delete_zip_file = False | |
| 252 failures = test.GetFailures() | |
| 253 if not failures or len(failures) != 2: | |
| 254 print "Did not get expected number of failures :" | |
| 255 for failure in failures: | |
| 256 print failure.test_path | |
| 257 test_result = False | |
| 258 finally: | |
| 259 os.remove(TEST_BUILDER_LOG_FILE) | |
| 260 os.remove(TEST_ARCHIVE_LOG_FILE) | |
| 261 os.remove(TEST_EXPECTATIONS_FILE) | |
| 262 os.remove(TEST_DUMMY_ZIP_FILE) | |
| 263 return test_result | |
| 264 | |
| 265 | |
| 266 def _writeFile(filename, contents): | |
| 267 myfile = open(filename, 'w') | |
| 268 myfile.write(contents) | |
| 269 myfile.close() | |
| 270 | |
| 271 | |
| 272 def testZipDownload(): | |
| 273 test = _getBasicFailureFinder() | |
| 274 try: | |
| 275 test._DownloadFile(TEST_ZIP_FILE, "test.zip", "b") # "b" -> binary | |
| 276 os.remove("test.zip") | |
| 277 return True | |
| 278 except: | |
| 279 return False | |
| 280 | |
| 281 | |
| 282 def testTranslateBuildToZip(): | |
| 283 test = _getBasicFailureFinder() | |
| 284 test.build = WEBKIT_BUILDER_NUMBER | |
| 285 revision, build_name = test._GetRevisionAndBuildFromArchiveStep() | |
| 286 if revision != EXPECTED_REVISION or build_name != EXPECTED_BUILD_NAME: | |
| 287 return False | |
| 288 return True | |
| 289 | |
| 290 | |
| 291 def testGetBaseline(): | |
| 292 test = _getBasicFailureFinder() | |
| 293 result = True | |
| 294 test.platform = "chromium-mac" | |
| 295 baseline = test._GetBaseline(WEBARCHIVE_TEST_EXPECTATION, ".") | |
| 296 if not baseline.local_file or baseline.baseline_url.find(WEBKIT_ORG) == -1: | |
| 297 result = False | |
| 298 print "Webarchive layout test not found at webkit.org: %s" % url | |
| 299 test.platform = "chromium-win" | |
| 300 baseline = test._GetBaseline(SVG_TEST_EXPECTATION, ".") | |
| 301 if (not baseline.local_file or | |
| 302 baseline.baseline_url.find(CHROMIUM_ORG) == -1): | |
| 303 result = False | |
| 304 print "SVG layout test found at %s, not chromium.org" % url | |
| 305 baseline = test._GetBaseline(SVG_TEST_EXPECTATION, ".", True) | |
| 306 if not baseline.local_file or baseline.baseline_url.find(WEBKIT_ORG) == -1: | |
| 307 result = False | |
| 308 print "Upstream SVG layout test NOT found at webkit.org!" | |
| 309 baseline = test._GetBaseline(DOM_TEST_EXPECTATION, ".", True) | |
| 310 if (not baseline.local_file or | |
| 311 baseline.baseline_url.find("/platform/") > -1): | |
| 312 result = False | |
| 313 print ("Upstream SVG layout test found in a " | |
| 314 "platform directory: %s" % url) | |
| 315 os.remove(WEBARCHIVE_TEST_EXPECTATION) | |
| 316 os.remove(SVG_TEST_EXPECTATION) | |
| 317 os.remove(SVG_TEST_EXPECTATION_UPSTREAM) | |
| 318 os.remove(DOM_TEST_EXPECTATION_UPSTREAM) | |
| 319 deleteDir("LayoutTests") | |
| 320 return result | |
| 321 | |
| 322 | |
| 323 def deleteDir(directory): | |
| 324 """ Recursively deletes empty directories given a root. | |
| 325 This method will throw an exception if they are not empty. """ | |
| 326 for root, dirs, files in os.walk(directory, topdown=False): | |
| 327 for d in dirs: | |
| 328 try: | |
| 329 os.rmdir(os.path.join(root, d)) | |
| 330 except: | |
| 331 pass | |
| 332 os.rmdir(directory) | |
| 333 | |
| 334 | |
| 335 def testFull(): | |
| 336 """ Verifies that the entire system works end-to-end. """ | |
| 337 test = _getBasicFailureFinder() | |
| 338 test.build = WEBKIT_BUILDER_NUMBER | |
| 339 test.dont_download = True # Dry run only, no downloading needed. | |
| 340 failures = test.GetFailures() | |
| 341 # Verify that the max failures parameter works. | |
| 342 if not failures or len(failures) > 10: | |
| 343 "Got no failures or too many failures." | |
| 344 return False | |
| 345 | |
| 346 # Verify the failures match the list of expected failures. | |
| 347 for failure in failures: | |
| 348 if not (failure.test_path in WEBKIT_FAILURES): | |
| 349 print "Found a failure I did not expect to see." | |
| 350 return False | |
| 351 | |
| 352 return True | |
| 353 | |
| 354 | |
| 355 def testFindTestExpectations(): | |
| 356 test = _getBasicFailureFinder() | |
| 357 test._test_expectations_cache = TEST_EXPECTATIONS | |
| 358 match = test._GetTestExpectationsLine(EXPECT_EXACT_MATCH) | |
| 359 if not match: | |
| 360 return False | |
| 361 match = test._GetTestExpectationsLine(EXPECT_GENERAL_MATCH) | |
| 362 if not match: | |
| 363 return False | |
| 364 match = test._GetTestExpectationsLine(EXPECT_NO_MATCH) | |
| 365 return not match | |
| 366 | |
| 367 | |
| 368 if __name__ == "__main__": | |
| 369 fft = FailureFinderTest() | |
| 370 result = fft.runTests() | |
| 371 if result: | |
| 372 print "All tests passed." | |
| 373 else: | |
| 374 print "Not all tests passed." | |
| OLD | NEW |