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 generated_data_dir = os.path.join(test_data_dir, 'generated') | |
19 ref_image_dir = os.path.join(test_data_dir, 'gpu_reference') | |
Ken Russell (switch to Gerrit)
2013/10/16 00:37:33
Could you rename these to something like "default_
| |
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 img_dir: | |
106 img_dir = ref_image_dir | |
107 | |
108 if not cur_revision: | |
109 cur_revision = 0 | |
110 | |
111 image_path = os.path.join(img_dir, img_name) | |
112 | |
113 PixelValidator.DeleteOldReferenceImages(image_path, cur_revision) | |
114 | |
115 image_path = image_path + '_' + str(cur_revision) + '.png' | |
116 | |
117 try: | |
118 ref_png = png_bitmap.PngBitmap.FromFile(image_path) | |
119 except IOError: | |
120 ref_png = None | |
121 | |
122 if ref_png: | |
123 return ref_png | |
124 | |
125 print 'Reference image not found. Writing tab contents as reference.' | |
126 | |
127 PixelValidator.WriteImage(image_path, screenshot) | |
128 return screenshot | |
129 | |
130 @staticmethod | |
131 def WriteErrorImages(img_dir, img_name, build_revision, screenshot, ref_png): | |
132 if not img_dir: | |
133 img_dir = generated_data_dir | |
134 | |
135 if not chrome_revision: | |
136 chrome_revision = "unknownrev" | |
137 | |
138 full_image_name = img_name + '_' + str(build_revision) | |
139 full_image_name = full_image_name + '.png' | |
140 | |
141 PixelValidator.WriteImage( | |
142 os.path.join(img_dir, 'FAIL_' + full_image_name), screenshot) | |
143 | |
144 diff_png = screenshot.Diff(ref_png) | |
145 PixelValidator.WriteImage( | |
146 os.path.join(img_dir, 'DIFF_' + full_image_name), diff_png) | |
147 | |
148 @staticmethod | |
149 def WriteImage(image_path, png_image): | |
150 output_dir = os.path.dirname(image_path) | |
151 if not os.path.exists(output_dir): | |
152 os.makedirs(output_dir) | |
153 | |
154 png_image.WriteFile(image_path) | |
21 | 155 |
22 class Pixel(test.Test): | 156 class Pixel(test.Test): |
23 enabled = False | 157 enabled = False |
24 test = PixelValidator | 158 test = PixelValidator |
25 page_set = 'page_sets/pixel_tests.json' | 159 page_set = 'page_sets/pixel_tests.json' |
160 | |
161 @staticmethod | |
162 def AddTestCommandLineOptions(parser): | |
163 group = optparse.OptionGroup(parser, 'Pixel test options') | |
164 group.add_option('--generated-dir', | |
165 help='Overrides the default location for generated test images that do ' | |
166 'not match reference images') | |
167 group.add_option('--reference-dir', | |
168 help='Overrides the default location for reference images') | |
Ken Russell (switch to Gerrit)
2013/10/16 00:37:33
Can you use "default=" to get rid of the if-tests
| |
169 group.add_option('--build-revision', | |
170 help='Chrome revision being tested.') | |
171 group.add_option('--gtest_output', | |
172 help='Ignored argument for compatibility with runtest.py harness') | |
173 parser.add_option_group(group) | |
174 | |
175 def CreateExpectations(self, page_set): | |
176 print page_set.pages | |
177 for page in page_set.pages: | |
178 page.script_to_evaluate_on_commit = test_harness_script | |
179 | |
180 return test_expectations.TestExpectations() | |
OLD | NEW |