OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 from datetime import datetime |
| 5 import glob |
| 6 import optparse |
| 7 import os |
| 8 import re |
| 9 |
4 from telemetry import test | 10 from telemetry import test |
| 11 from telemetry.core.backends import png_bitmap |
5 from telemetry.page import page_test | 12 from telemetry.page import page_test |
| 13 from telemetry.page import test_expectations |
6 | 14 |
| 15 test_data_dir = os.path.abspath(os.path.join( |
| 16 os.path.dirname(__file__), '..', '..', 'data', 'gpu')) |
| 17 |
| 18 default_generated_data_dir = os.path.join(test_data_dir, 'generated') |
| 19 default_reference_image_dir = os.path.join(test_data_dir, 'gpu_reference') |
| 20 |
| 21 test_harness_script = r""" |
| 22 var domAutomationController = {}; |
| 23 |
| 24 domAutomationController._succeeded = false; |
| 25 domAutomationController._finished = false; |
| 26 |
| 27 domAutomationController.setAutomationId = function(id) {} |
| 28 |
| 29 domAutomationController.send = function(msg) { |
| 30 domAutomationController._finished = true; |
| 31 |
| 32 if(msg.toLowerCase() == "success") { |
| 33 domAutomationController._succeeded = true; |
| 34 } else { |
| 35 domAutomationController._succeeded = false; |
| 36 } |
| 37 } |
| 38 |
| 39 window.domAutomationController = domAutomationController; |
| 40 console.log("Harness injected."); |
| 41 """ |
7 | 42 |
8 class PixelTestFailure(Exception): | 43 class PixelTestFailure(Exception): |
9 pass | 44 pass |
10 | 45 |
| 46 def _DidTestSucceed(tab): |
| 47 return tab.EvaluateJavaScript('domAutomationController._succeeded') |
11 | 48 |
12 class PixelValidator(page_test.PageTest): | 49 class PixelValidator(page_test.PageTest): |
13 def __init__(self): | 50 def __init__(self): |
14 super(PixelValidator, self).__init__('ValidatePage') | 51 super(PixelValidator, self).__init__('ValidatePage') |
15 | 52 |
| 53 def CustomizeBrowserOptions(self, options): |
| 54 options.AppendExtraBrowserArgs('--enable-gpu-benchmarking') |
| 55 |
16 def ValidatePage(self, page, tab, results): | 56 def ValidatePage(self, page, tab, results): |
17 # TODO(bajones): Grab screenshot, compare to reference. | 57 if not _DidTestSucceed(tab): |
18 # page.reference_image | 58 raise page_test.Failure('Page indicated a failure') |
19 pass | |
20 | 59 |
| 60 if not tab.screenshot_supported: |
| 61 raise page_test.Failure('Browser does not support screenshot capture') |
| 62 |
| 63 screenshot = tab.Screenshot(5) |
| 64 |
| 65 if not screenshot: |
| 66 raise page_test.Failure('Could not capture screenshot') |
| 67 |
| 68 if hasattr(page, 'test_rect'): |
| 69 screenshot = screenshot.Crop( |
| 70 page.test_rect[0], page.test_rect[1], |
| 71 page.test_rect[2], page.test_rect[3]) |
| 72 |
| 73 image_name = PixelValidator.UrlToImageName(page.display_name) |
| 74 |
| 75 ref_png = PixelValidator.GetReferenceImage(self.options.reference_dir, |
| 76 image_name, page.revision, screenshot) |
| 77 |
| 78 # Test new snapshot against existing reference image |
| 79 if not ref_png.IsEqual(screenshot, tolerance=2): |
| 80 PixelValidator.WriteErrorImages(self.options.generated_dir, image_name, |
| 81 self.options.build_revision, screenshot, ref_png) |
| 82 raise page_test.Failure('Reference image did not match captured screen') |
| 83 |
| 84 @staticmethod |
| 85 def UrlToImageName(url): |
| 86 image_name = re.sub(r'^(http|https|file)://(/*)', '', url) |
| 87 image_name = re.sub(r'\.\./', '', image_name) |
| 88 image_name = re.sub(r'(\.|/|-)', '_', image_name) |
| 89 return image_name |
| 90 |
| 91 @staticmethod |
| 92 def DeleteOldReferenceImages(ref_image_path, cur_revision): |
| 93 if not cur_revision: |
| 94 return |
| 95 |
| 96 old_revisions = glob.glob(ref_image_path + "_*.png") |
| 97 for rev_path in old_revisions: |
| 98 m = re.match(r'^.*_(\d+)\.png$', rev_path) |
| 99 if m and int(m.group(1)) < cur_revision: |
| 100 print 'Found deprecated reference image. Deleting rev ' + m.group(1) |
| 101 os.remove(rev_path) |
| 102 |
| 103 @staticmethod |
| 104 def GetReferenceImage(img_dir, img_name, cur_revision, screenshot): |
| 105 if not cur_revision: |
| 106 cur_revision = 0 |
| 107 |
| 108 image_path = os.path.join(img_dir, img_name) |
| 109 |
| 110 PixelValidator.DeleteOldReferenceImages(image_path, cur_revision) |
| 111 |
| 112 image_path = image_path + '_' + str(cur_revision) + '.png' |
| 113 |
| 114 try: |
| 115 ref_png = png_bitmap.PngBitmap.FromFile(image_path) |
| 116 except IOError: |
| 117 ref_png = None |
| 118 |
| 119 if ref_png: |
| 120 return ref_png |
| 121 |
| 122 print 'Reference image not found. Writing tab contents as reference.' |
| 123 |
| 124 PixelValidator.WriteImage(image_path, screenshot) |
| 125 return screenshot |
| 126 |
| 127 @staticmethod |
| 128 def WriteErrorImages(img_dir, img_name, build_revision, screenshot, ref_png): |
| 129 full_image_name = img_name + '_' + str(build_revision) |
| 130 full_image_name = full_image_name + '.png' |
| 131 |
| 132 PixelValidator.WriteImage( |
| 133 os.path.join(img_dir, 'FAIL_' + full_image_name), screenshot) |
| 134 |
| 135 diff_png = screenshot.Diff(ref_png) |
| 136 PixelValidator.WriteImage( |
| 137 os.path.join(img_dir, 'DIFF_' + full_image_name), diff_png) |
| 138 |
| 139 @staticmethod |
| 140 def WriteImage(image_path, png_image): |
| 141 output_dir = os.path.dirname(image_path) |
| 142 if not os.path.exists(output_dir): |
| 143 os.makedirs(output_dir) |
| 144 |
| 145 png_image.WriteFile(image_path) |
21 | 146 |
22 class Pixel(test.Test): | 147 class Pixel(test.Test): |
23 enabled = False | 148 enabled = False |
24 test = PixelValidator | 149 test = PixelValidator |
25 page_set = 'page_sets/pixel_tests.json' | 150 page_set = 'page_sets/pixel_tests.json' |
| 151 |
| 152 @staticmethod |
| 153 def AddTestCommandLineOptions(parser): |
| 154 group = optparse.OptionGroup(parser, 'Pixel test options') |
| 155 group.add_option('--generated-dir', |
| 156 help='Overrides the default location for generated test images that do ' |
| 157 'not match reference images', |
| 158 default=default_generated_data_dir) |
| 159 group.add_option('--reference-dir', |
| 160 help='Overrides the default location for reference images', |
| 161 default=default_reference_image_dir) |
| 162 group.add_option('--build-revision', |
| 163 help='Chrome revision being tested.', |
| 164 default="unknownrev") |
| 165 group.add_option('--gtest_output', |
| 166 help='Ignored argument for compatibility with runtest.py harness') |
| 167 parser.add_option_group(group) |
| 168 |
| 169 def CreateExpectations(self, page_set): |
| 170 print page_set.pages |
| 171 for page in page_set.pages: |
| 172 page.script_to_evaluate_on_commit = test_harness_script |
| 173 |
| 174 return test_expectations.TestExpectations() |
OLD | NEW |