Chromium Code Reviews| 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 """Base classes for a test and validator which upload results | 5 """Base classes for a test and validator which upload results | 
| 6 (reference images, error images) to cloud storage.""" | 6 (reference images, error images) to cloud storage.""" | 
| 7 | 7 | 
| 8 import os | 8 import os | 
| 9 import re | 9 import re | 
| 10 import tempfile | 10 import tempfile | 
| 11 | 11 | 
| 12 import cv2 | |
| 
 
tonyg
2014/10/21 16:12:56
Nit: alphabetize
 
mthiesse
2014/10/22 15:33:09
Done.
 
 | |
| 13 | |
| 12 from telemetry import benchmark | 14 from telemetry import benchmark | 
| 13 from telemetry.core import bitmap | 15 from telemetry.core import bitmap | 
| 14 from telemetry.page import page_test | 16 from telemetry.page import page_test | 
| 15 from telemetry.util import cloud_storage | 17 from telemetry.util import cloud_storage | 
| 16 | 18 | 
| 17 | 19 | 
| 18 test_data_dir = os.path.abspath(os.path.join( | 20 test_data_dir = os.path.abspath(os.path.join( | 
| 19 os.path.dirname(__file__), '..', '..', 'data', 'gpu')) | 21 os.path.dirname(__file__), '..', '..', 'data', 'gpu')) | 
| 20 | 22 | 
| 21 default_generated_data_dir = os.path.join(test_data_dir, 'generated') | 23 default_generated_data_dir = os.path.join(test_data_dir, 'generated') | 
| 22 | 24 | 
| 23 error_image_cloud_storage_bucket = 'chromium-browser-gpu-tests' | 25 error_image_cloud_storage_bucket = 'chromium-browser-gpu-tests' | 
| 24 | 26 | 
| 25 def _CompareScreenshotSamples(screenshot, expectations, device_pixel_ratio): | 27 def _CompareScreenshotSamples(screenshot, expectations, device_pixel_ratio): | 
| 26 for expectation in expectations: | 28 for expectation in expectations: | 
| 27 location = expectation["location"] | 29 location = expectation["location"] | 
| 28 x = int(location[0] * device_pixel_ratio) | 30 x = int(location[0] * device_pixel_ratio) | 
| 29 y = int(location[1] * device_pixel_ratio) | 31 y = int(location[1] * device_pixel_ratio) | 
| 30 | 32 | 
| 31 if x < 0 or y < 0 or x > screenshot.width or y > screenshot.height: | 33 if x < 0 or y < 0 or x > screenshot.width or y > screenshot.height: | 
| 32 raise page_test.Failure( | 34 raise page_test.Failure( | 
| 33 'Expected pixel location [%d, %d] is out of range on [%d, %d] image' % | 35 'Expected pixel location [%d, %d] is out of range on [%d, %d] image' % | 
| 34 (x, y, screenshot.width, screenshot.height)) | 36 (x, y, screenshot.width, screenshot.height)) | 
| 35 | 37 | 
| 36 actual_color = screenshot.GetPixelColor(x, y) | 38 actual_color = screenshot.image[y][x] | 
| 37 expected_color = bitmap.RgbaColor( | 39 expected_color = (expectation["color"][0], expectation["color"][1], | 
| 38 expectation["color"][0], | |
| 39 expectation["color"][1], | |
| 40 expectation["color"][2]) | 40 expectation["color"][2]) | 
| 
 
slamm
2014/10/21 23:21:58
Nit. Follow style-guide for indentation.
https://
 
mthiesse
2014/10/22 15:33:09
Done.
 
 | |
| 41 if not actual_color.IsEqual(expected_color, expectation["tolerance"]): | 41 if not bitmap.ColorsAreEqual(actual_color, expected_color, | 
| 42 expectation["tolerance"]): | |
| 
 
slamm
2014/10/21 23:21:58
Fix indentation (same issue as line 39).
 
mthiesse
2014/10/22 15:33:09
Done.
 
 | |
| 42 raise page_test.Failure('Expected pixel at ' + str(location) + | 43 raise page_test.Failure('Expected pixel at ' + str(location) + | 
| 43 ' to be ' + | 44 ' to be ' + | 
| 44 str(expectation["color"]) + " but got [" + | 45 str(expectation["color"]) + " but got [" + | 
| 45 str(actual_color.r) + ", " + | 46 str(actual_color[2]) + ", " + | 
| 46 str(actual_color.g) + ", " + | 47 str(actual_color[1]) + ", " + | 
| 47 str(actual_color.b) + "]") | 48 str(actual_color[0]) + "]") | 
| 
 
slamm
2014/10/21 23:21:58
Nit that precedes you. Use '%' formatting:
raise
 
mthiesse
2014/10/22 15:33:09
Done.
 
 | |
| 48 | 49 | 
| 49 class ValidatorBase(page_test.PageTest): | 50 class ValidatorBase(page_test.PageTest): | 
| 50 def __init__(self): | 51 def __init__(self): | 
| 51 super(ValidatorBase, self).__init__() | 52 super(ValidatorBase, self).__init__() | 
| 52 # Parameters for cloud storage reference images. | 53 # Parameters for cloud storage reference images. | 
| 53 self.vendor_id = None | 54 self.vendor_id = None | 
| 54 self.device_id = None | 55 self.device_id = None | 
| 55 self.vendor_string = None | 56 self.vendor_string = None | 
| 56 self.device_string = None | 57 self.device_string = None | 
| 57 self.msaa = False | 58 self.msaa = False | 
| 58 | 59 | 
| 59 ### | 60 ### | 
| 60 ### Routines working with the local disk (only used for local | 61 ### Routines working with the local disk (only used for local | 
| 61 ### testing without a cloud storage account -- the bots do not use | 62 ### testing without a cloud storage account -- the bots do not use | 
| 62 ### this code path). | 63 ### this code path). | 
| 63 ### | 64 ### | 
| 64 | 65 | 
| 65 def _UrlToImageName(self, url): | 66 def _UrlToImageName(self, url): | 
| 66 image_name = re.sub(r'^(http|https|file)://(/*)', '', url) | 67 image_name = re.sub(r'^(http|https|file)://(/*)', '', url) | 
| 67 image_name = re.sub(r'\.\./', '', image_name) | 68 image_name = re.sub(r'\.\./', '', image_name) | 
| 68 image_name = re.sub(r'(\.|/|-)', '_', image_name) | 69 image_name = re.sub(r'(\.|/|-)', '_', image_name) | 
| 69 return image_name | 70 return image_name | 
| 70 | 71 | 
| 71 def _WriteImage(self, image_path, png_image): | 72 def _WriteImage(self, image_path, png_image): | 
| 72 output_dir = os.path.dirname(image_path) | 73 output_dir = os.path.dirname(image_path) | 
| 73 if not os.path.exists(output_dir): | 74 if not os.path.exists(output_dir): | 
| 74 os.makedirs(output_dir) | 75 os.makedirs(output_dir) | 
| 75 png_image.WritePngFile(image_path) | 76 cv2.imwrite(image_path, png_image.image) | 
| 76 | 77 | 
| 77 def _WriteErrorImages(self, img_dir, img_name, screenshot, ref_png): | 78 def _WriteErrorImages(self, img_dir, img_name, screenshot, ref_png): | 
| 78 full_image_name = img_name + '_' + str(self.options.build_revision) | 79 full_image_name = img_name + '_' + str(self.options.build_revision) | 
| 79 full_image_name = full_image_name + '.png' | 80 full_image_name = full_image_name + '.png' | 
| 80 | 81 | 
| 81 # Always write the failing image. | 82 # Always write the failing image. | 
| 82 self._WriteImage( | 83 self._WriteImage( | 
| 83 os.path.join(img_dir, 'FAIL_' + full_image_name), screenshot) | 84 os.path.join(img_dir, 'FAIL_' + full_image_name), screenshot) | 
| 84 | 85 | 
| 85 if ref_png: | 86 if ref_png: | 
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 164 """Downloads the reference image for the given test from cloud | 165 """Downloads the reference image for the given test from cloud | 
| 165 storage, returning it as a Telemetry Bitmap object.""" | 166 storage, returning it as a Telemetry Bitmap object.""" | 
| 166 # TODO(kbr): there's a race condition between the deletion of the | 167 # TODO(kbr): there's a race condition between the deletion of the | 
| 167 # temporary file and gsutil's overwriting it. | 168 # temporary file and gsutil's overwriting it. | 
| 168 if not self.options.refimg_cloud_storage_bucket: | 169 if not self.options.refimg_cloud_storage_bucket: | 
| 169 raise Exception('--refimg-cloud-storage-bucket argument is required') | 170 raise Exception('--refimg-cloud-storage-bucket argument is required') | 
| 170 temp_file = tempfile.NamedTemporaryFile().name | 171 temp_file = tempfile.NamedTemporaryFile().name | 
| 171 cloud_storage.Get(self.options.refimg_cloud_storage_bucket, | 172 cloud_storage.Get(self.options.refimg_cloud_storage_bucket, | 
| 172 self._FormatReferenceImageName(img_name, page, tab), | 173 self._FormatReferenceImageName(img_name, page, tab), | 
| 173 temp_file) | 174 temp_file) | 
| 174 return bitmap.Bitmap.FromPngFile(temp_file) | 175 return bitmap.Bitmap.FromImageFile(temp_file) | 
| 175 | 176 | 
| 176 def _UploadErrorImagesToCloudStorage(self, image_name, screenshot, ref_img): | 177 def _UploadErrorImagesToCloudStorage(self, image_name, screenshot, ref_img): | 
| 177 """For a failing run, uploads the failing image, reference image (if | 178 """For a failing run, uploads the failing image, reference image (if | 
| 178 supplied), and diff image (if reference image was supplied) to cloud | 179 supplied), and diff image (if reference image was supplied) to cloud | 
| 179 storage. This subsumes the functionality of the | 180 storage. This subsumes the functionality of the | 
| 180 archive_gpu_pixel_test_results.py script.""" | 181 archive_gpu_pixel_test_results.py script.""" | 
| 181 machine_name = re.sub('\W+', '_', self.options.test_machine_name) | 182 machine_name = re.sub('\W+', '_', self.options.test_machine_name) | 
| 182 upload_dir = '%s_%s_telemetry' % (self.options.build_revision, machine_name) | 183 upload_dir = '%s_%s_telemetry' % (self.options.build_revision, machine_name) | 
| 183 base_bucket = '%s/runs/%s' % (error_image_cloud_storage_bucket, upload_dir) | 184 base_bucket = '%s/runs/%s' % (error_image_cloud_storage_bucket, upload_dir) | 
| 184 image_name_with_revision = '%s_%s.png' % ( | 185 image_name_with_revision = '%s_%s.png' % ( | 
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 244 default='') | 245 default='') | 
| 245 group.add_option('--test-machine-name', | 246 group.add_option('--test-machine-name', | 
| 246 help='Name of the test machine. Specifying this argument causes this ' | 247 help='Name of the test machine. Specifying this argument causes this ' | 
| 247 'script to upload failure images and diffs to cloud storage directly, ' | 248 'script to upload failure images and diffs to cloud storage directly, ' | 
| 248 'instead of relying on the archive_gpu_pixel_test_results.py script.', | 249 'instead of relying on the archive_gpu_pixel_test_results.py script.', | 
| 249 default='') | 250 default='') | 
| 250 group.add_option('--generated-dir', | 251 group.add_option('--generated-dir', | 
| 251 help='Overrides the default on-disk location for generated test images ' | 252 help='Overrides the default on-disk location for generated test images ' | 
| 252 '(only used for local testing without a cloud storage account)', | 253 '(only used for local testing without a cloud storage account)', | 
| 253 default=default_generated_data_dir) | 254 default=default_generated_data_dir) | 
| OLD | NEW |