OLD | NEW |
---|---|
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 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 | 4 |
5 """Runs a Google Maps pixel test. | 5 """Runs a Google Maps pixel test. |
6 Performs several common navigation actions on the map (pan, zoom, rotate) then | 6 Performs several common navigation actions on the map (pan, zoom, rotate) then |
7 captures a screenshot and compares selected pixels against expected values""" | 7 captures a screenshot and compares selected pixels against expected values""" |
8 | 8 |
9 import json | 9 import json |
10 import optparse | |
10 import os | 11 import os |
11 import re | 12 import re |
12 | 13 |
14 import maps_expectations | |
15 | |
13 from telemetry import test | 16 from telemetry import test |
14 from telemetry.core.backends import png_bitmap | 17 from telemetry.core.backends import png_bitmap |
15 from telemetry.core import util | 18 from telemetry.core import util |
16 from telemetry.page import page_test | 19 from telemetry.page import page_test |
17 from telemetry.page import page_set | 20 from telemetry.page import page_set |
18 | 21 |
22 test_data_dir = os.path.abspath(os.path.join( | |
23 os.path.dirname(__file__), '..', '..', 'data', 'gpu')) | |
24 | |
25 default_generated_data_dir = os.path.join(test_data_dir, 'generated') | |
26 | |
19 class MapsValidator(page_test.PageTest): | 27 class MapsValidator(page_test.PageTest): |
20 def __init__(self): | 28 def __init__(self): |
21 super(MapsValidator, self).__init__('ValidatePage') | 29 super(MapsValidator, self).__init__('ValidatePage') |
22 | 30 |
23 def CustomizeBrowserOptions(self, options): | 31 def CustomizeBrowserOptions(self, options): |
24 options.AppendExtraBrowserArgs('--enable-gpu-benchmarking') | 32 options.AppendExtraBrowserArgs('--enable-gpu-benchmarking') |
25 | 33 |
26 def ValidatePage(self, page, tab, results): | 34 def ValidatePage(self, page, tab, results): |
35 MapsValidator.SpinWaitOnRAF(tab, 3) | |
Ken Russell (switch to Gerrit)
2013/11/19 01:22:30
Please add a TODO about removing this, since theor
bajones
2013/11/19 18:27:31
Done.
| |
36 | |
27 if not tab.screenshot_supported: | 37 if not tab.screenshot_supported: |
28 raise page_test.Failure('Browser does not support screenshot capture') | 38 raise page_test.Failure('Browser does not support screenshot capture') |
29 screenshot = tab.Screenshot(5) | 39 screenshot = tab.Screenshot(5) |
30 if not screenshot: | 40 if not screenshot: |
31 raise page_test.Failure('Could not capture screenshot') | 41 raise page_test.Failure('Could not capture screenshot') |
32 | 42 |
43 dpr = tab.EvaluateJavaScript('window.devicePixelRatio') | |
33 expected = MapsValidator.ReadPixelExpectations(page) | 44 expected = MapsValidator.ReadPixelExpectations(page) |
34 MapsValidator.CompareToExpectations(screenshot, expected) | 45 |
46 try: | |
47 MapsValidator.CompareToExpectations(screenshot, expected, dpr) | |
48 except page_test.Failure: | |
49 image_name = MapsValidator.UrlToImageName(page.display_name) | |
50 MapsValidator.WriteErrorImage(self.options.generated_dir, | |
51 image_name, self.options.build_revision, screenshot) | |
52 raise | |
53 | |
54 @staticmethod | |
55 def SpinWaitOnRAF(tab, iterations, timeout = 60): | |
56 waitScript = r""" | |
57 window.__spinWaitOnRAFDone = false; | |
58 var iterationsLeft = %d; | |
59 | |
60 function spin() { | |
61 iterationsLeft--; | |
62 if (iterationsLeft == 0) { | |
63 window.__spinWaitOnRAFDone = true; | |
64 return; | |
65 } | |
66 window.requestAnimationFrame(spin); | |
67 } | |
68 window.requestAnimationFrame(spin); | |
69 """ % iterations | |
70 | |
71 def IsWaitComplete(): | |
72 return tab.EvaluateJavaScript('window.__spinWaitOnRAFDone') | |
73 | |
74 tab.ExecuteJavaScript(waitScript) | |
75 util.WaitFor(IsWaitComplete, timeout) | |
35 | 76 |
36 @staticmethod | 77 @staticmethod |
37 def ReadPixelExpectations(page): | 78 def ReadPixelExpectations(page): |
38 expectations_path = os.path.join(page._base_dir, page.pixel_expectations) | 79 expectations_path = os.path.join(page._base_dir, page.pixel_expectations) |
39 with open(expectations_path, 'r') as f: | 80 with open(expectations_path, 'r') as f: |
40 json_contents = json.load(f) | 81 json_contents = json.load(f) |
41 return json_contents | 82 return json_contents |
42 | 83 |
43 @staticmethod | 84 @staticmethod |
44 def CompareToExpectations(screenshot, expectations): | 85 def CompareToExpectations(screenshot, expectations, devicePixelRatio): |
45 for expectation in expectations: | 86 for expectation in expectations: |
46 location = expectation["location"] | 87 location = expectation["location"] |
47 pixel_color = screenshot.GetPixelColor(location[0], location[1]) | 88 pixel_color = screenshot.GetPixelColor( |
89 location[0] * devicePixelRatio, | |
90 location[1] * devicePixelRatio) | |
48 expect_color = png_bitmap.PngColor( | 91 expect_color = png_bitmap.PngColor( |
49 expectation["color"][0], | 92 expectation["color"][0], |
50 expectation["color"][1], | 93 expectation["color"][1], |
51 expectation["color"][2]) | 94 expectation["color"][2]) |
52 iter_result = pixel_color.IsEqual(expect_color, expectation["tolerance"]) | 95 iter_result = pixel_color.IsEqual(expect_color, expectation["tolerance"]) |
53 if not iter_result: | 96 if not iter_result: |
54 raise page_test.Failure('FAILURE: Expected pixel at ' + str(location) + | 97 raise page_test.Failure('FAILURE: Expected pixel at ' + str(location) + |
55 ' to be ' + | 98 ' to be ' + |
56 str(expectation["color"]) + " but got [" + | 99 str(expectation["color"]) + " but got [" + |
57 str(pixel_color.r) + ", " + | 100 str(pixel_color.r) + ", " + |
58 str(pixel_color.g) + ", " + | 101 str(pixel_color.g) + ", " + |
59 str(pixel_color.b) + "]") | 102 str(pixel_color.b) + "]") |
60 | 103 |
104 @staticmethod | |
105 def UrlToImageName(url): | |
106 image_name = re.sub(r'^(http|https|file)://(/*)', '', url) | |
107 image_name = re.sub(r'\.\./', '', image_name) | |
108 image_name = re.sub(r'(\.|/|-)', '_', image_name) | |
109 return image_name | |
110 | |
111 @staticmethod | |
112 def WriteErrorImage(img_dir, img_name, build_revision, screenshot): | |
113 full_image_name = img_name + '_' + str(build_revision) | |
114 full_image_name = full_image_name + '.png' | |
115 | |
116 # This is a nasty and temporary hack: The pixel test archive step will copy | |
117 # DIFF images directly, but for FAIL images it also requires a ref. This | |
118 # allows us to archive the erronous image while the archiving step is being | |
119 # refactored | |
120 image_path = os.path.join(img_dir, 'DIFF_' + full_image_name) | |
121 | |
122 output_dir = os.path.dirname(image_path) | |
123 if not os.path.exists(output_dir): | |
124 os.makedirs(output_dir) | |
125 | |
126 screenshot.WriteFile(image_path) | |
127 | |
61 class Maps(test.Test): | 128 class Maps(test.Test): |
62 """Google Maps pixel tests.""" | 129 """Google Maps pixel tests.""" |
63 test = MapsValidator | 130 test = MapsValidator |
64 | 131 |
132 @staticmethod | |
133 def AddTestCommandLineOptions(parser): | |
134 group = optparse.OptionGroup(parser, 'Maps test options') | |
135 group.add_option('--generated-dir', | |
136 help='Overrides the default location for generated test images that ' | |
137 'fail expectations checks', | |
138 default=default_generated_data_dir) | |
139 group.add_option('--build-revision', | |
140 help='Chrome revision being tested.', | |
141 default="unknownrev") | |
Ken Russell (switch to Gerrit)
2013/11/19 01:22:30
Presumably this command line argument will be adde
bajones
2013/11/19 18:27:31
The maps test has been removed from the recipe at
| |
142 parser.add_option_group(group) | |
143 | |
144 def CreateExpectations(self, page_set): | |
145 return maps_expectations.MapsExpectations() | |
146 | |
65 def CreatePageSet(self, options): | 147 def CreatePageSet(self, options): |
66 page_set_path = os.path.join( | 148 page_set_path = os.path.join( |
67 util.GetChromiumSrcDir(), 'content', 'test', 'gpu', 'page_sets') | 149 util.GetChromiumSrcDir(), 'content', 'test', 'gpu', 'page_sets') |
68 page_set_dict = { | 150 page_set_dict = { |
69 'archive_data_file': 'data/maps.json', | 151 'archive_data_file': 'data/maps.json', |
70 'make_javascript_deterministic': False, | 152 'make_javascript_deterministic': False, |
71 'pages': [ | 153 'pages': [ |
72 { | 154 { |
155 'name': 'Maps.maps_001', | |
73 'url': 'http://localhost:10020/tracker.html', | 156 'url': 'http://localhost:10020/tracker.html', |
74 'navigate_steps': [ | 157 'navigate_steps': [ |
75 { 'action': 'navigate' }, | 158 { 'action': 'navigate' }, |
76 { 'action': 'wait', 'javascript': 'window.testDone' } | 159 { 'action': 'wait', 'javascript': 'window.testDone' } |
77 ], | 160 ], |
78 'pixel_expectations': 'data/maps_001_expectations.json' | 161 'pixel_expectations': 'data/maps_001_expectations.json' |
79 } | 162 } |
80 ] | 163 ] |
81 } | 164 } |
82 | 165 |
83 return page_set.PageSet.FromDict(page_set_dict, page_set_path) | 166 return page_set.PageSet.FromDict(page_set_dict, page_set_path) |
OLD | NEW |