| Index: content/test/gpu/gpu_tests/pixel.py
|
| diff --git a/content/test/gpu/gpu_tests/pixel.py b/content/test/gpu/gpu_tests/pixel.py
|
| index c6916eeef622aa35019feb76021962f9c04adf04..7a2da92da7a2ca4cce5224756c7358ca1b0a6856 100644
|
| --- a/content/test/gpu/gpu_tests/pixel.py
|
| +++ b/content/test/gpu/gpu_tests/pixel.py
|
| @@ -6,9 +6,11 @@ import glob
|
| import optparse
|
| import os
|
| import re
|
| +import tempfile
|
|
|
| from telemetry import test
|
| from telemetry.core import bitmap
|
| +from telemetry.page import cloud_storage
|
| from telemetry.page import page_test
|
|
|
| test_data_dir = os.path.abspath(os.path.join(
|
| @@ -17,6 +19,8 @@ test_data_dir = os.path.abspath(os.path.join(
|
| default_generated_data_dir = os.path.join(test_data_dir, 'generated')
|
| default_reference_image_dir = os.path.join(test_data_dir, 'gpu_reference')
|
|
|
| +error_image_cloud_storage_bucket = 'chromium-browser-gpu-tests'
|
| +
|
| test_harness_script = r"""
|
| var domAutomationController = {};
|
|
|
| @@ -47,6 +51,11 @@ def _DidTestSucceed(tab):
|
| class PixelValidator(page_test.PageTest):
|
| def __init__(self):
|
| super(PixelValidator, self).__init__('ValidatePage')
|
| + # Parameters for cloud storage reference images.
|
| + self.vendor_id = None
|
| + self.device_id = None
|
| + self.vendor_string = None
|
| + self.device_string = None
|
|
|
| def CustomizeBrowserOptions(self, options):
|
| options.AppendExtraBrowserArgs('--enable-gpu-benchmarking')
|
| @@ -70,13 +79,31 @@ class PixelValidator(page_test.PageTest):
|
|
|
| image_name = PixelValidator.UrlToImageName(page.display_name)
|
|
|
| - ref_png = PixelValidator.GetReferenceImage(self.options.reference_dir,
|
| - image_name, page.revision, screenshot)
|
| + if self.options.upload_refimg_to_cloud_storage:
|
| + if self._ConditionallyUploadToCloudStorage(image_name, page, tab,
|
| + screenshot):
|
| + # This is the new reference image; there's nothing to compare against.
|
| + ref_png = screenshot
|
| + else:
|
| + # There was a preexisting reference image, so we might as well
|
| + # compare against it.
|
| + ref_png = self._DownloadFromCloudStorage(image_name, page, tab)
|
| + elif self.options.download_refimg_from_cloud_storage:
|
| + # This bot doesn't have the ability to properly generate a
|
| + # reference image, so download it from cloud storage.
|
| + ref_png = self._DownloadFromCloudStorage(image_name, page, tab)
|
| + else:
|
| + # Legacy path using on-disk results.
|
| + ref_png = PixelValidator.GetReferenceImage(self.options.reference_dir,
|
| + image_name, page.revision, screenshot)
|
|
|
| # Test new snapshot against existing reference image
|
| if not ref_png.IsEqual(screenshot, tolerance=2):
|
| - PixelValidator.WriteErrorImages(self.options.generated_dir, image_name,
|
| - self.options.build_revision, screenshot, ref_png)
|
| + if self.options.test_machine_name:
|
| + self._UploadErrorImagesToCloudStorage(image_name, ref_png, screenshot)
|
| + else:
|
| + PixelValidator.WriteErrorImages(self.options.generated_dir, image_name,
|
| + self.options.build_revision, screenshot, ref_png)
|
| raise page_test.Failure('Reference image did not match captured screen')
|
|
|
| @staticmethod
|
| @@ -147,6 +174,103 @@ class PixelValidator(page_test.PageTest):
|
|
|
| png_image.WritePngFile(image_path)
|
|
|
| + def _ComputeGpuInfo(self, tab):
|
| + if ((self.vendor_id and self.device_id) or
|
| + (self.vendor_string and self.device_string)):
|
| + return
|
| + browser = tab.browser
|
| + if not browser.supports_system_info:
|
| + raise Exception('System info must be supported by the browser')
|
| + system_info = browser.GetSystemInfo()
|
| + if not system_info.gpu:
|
| + raise Exception('GPU information was absent')
|
| + device = system_info.gpu.devices[0]
|
| + if device.vendor_id and device.device_id:
|
| + self.vendor_id = device.vendor_id
|
| + self.device_id = device.device_id
|
| + elif device.vendor_string and device.device_string:
|
| + self.vendor_string = device.vendor_string
|
| + self.device_string = device.device_string
|
| + else:
|
| + raise Exception('GPU device information was incomplete')
|
| +
|
| + def _FormatGpuInfo(self, tab):
|
| + self._ComputeGpuInfo(tab)
|
| + if self.vendor_id:
|
| + return '%s_%04x_%04x' % (
|
| + self.options.os_type, self.vendor_id, self.device_id)
|
| + else:
|
| + return '%s_%s_%s' % (
|
| + self.options.os_type, self.vendor_string, self.device_string)
|
| +
|
| + def _FormatReferenceImageName(self, img_name, page, tab):
|
| + return '%s_v%s_%s.png' % (
|
| + img_name,
|
| + page.revision,
|
| + self._FormatGpuInfo(tab))
|
| +
|
| + def _UploadBitmapToCloudStorage(self, bucket, name, bitmap, public=False):
|
| + # This sequence of steps works on all platforms to write a temporary
|
| + # PNG to disk, following the pattern in bitmap_unittest.py. The key to
|
| + # avoiding PermissionErrors seems to be to not actually try to write to
|
| + # the temporary file object, but to re-open its name for all operations.
|
| + f = tempfile.NamedTemporaryFile()
|
| + bitmap.WritePngFile(f.name)
|
| + cloud_storage.Insert(bucket, name, f.name, publicly_readable=public)
|
| + f.close()
|
| +
|
| + def _ConditionallyUploadToCloudStorage(self, img_name, page, tab, screenshot):
|
| + """Uploads the screenshot to cloud storage as the reference image
|
| + for this test, unless it already exists. Returns True if the
|
| + upload was actually performed."""
|
| + if not self.options.refimg_cloud_storage_bucket:
|
| + raise Exception('--refimg-cloud-storage-bucket argument is required')
|
| + cloud_name = self._FormatReferenceImageName(img_name, page, tab)
|
| + if not cloud_storage.Exists(self.options.refimg_cloud_storage_bucket,
|
| + cloud_name):
|
| + self._UploadBitmapToCloudStorage(self.options.refimg_cloud_storage_bucket,
|
| + cloud_name,
|
| + screenshot)
|
| + return True
|
| + return False
|
| +
|
| + def _DownloadFromCloudStorage(self, img_name, page, tab):
|
| + """Downloads the reference image for the given test from cloud
|
| + storage, returning it as a Telemetry Bitmap object."""
|
| + # TODO(kbr): there's a race condition between the deletion of the
|
| + # temporary file and gsutil's overwriting it.
|
| + if not self.options.refimg_cloud_storage_bucket:
|
| + raise Exception('--refimg-cloud-storage-bucket argument is required')
|
| + f = tempfile.NamedTemporaryFile()
|
| + filename = f.name
|
| + f.close()
|
| + cloud_storage.Get(self.options.refimg_cloud_storage_bucket,
|
| + self._FormatReferenceImageName(img_name, page, tab),
|
| + filename)
|
| + return bitmap.Bitmap.FromPngFile(filename)
|
| +
|
| + def _UploadErrorImagesToCloudStorage(self, image_name, ref_img, screenshot):
|
| + """For a failing run, uploads the reference image, failing image,
|
| + and diff image to cloud storage. This subsumes the functionality
|
| + of the archive_gpu_pixel_test_results.py script."""
|
| + machine_name = re.sub('\W+', '_', self.options.test_machine_name)
|
| + upload_dir = '%s_%s_telemetry' % (self.options.build_revision, machine_name)
|
| + base_bucket = '%s/runs/%s' % (error_image_cloud_storage_bucket, upload_dir)
|
| + image_name_with_revision = '%s_%s.png' % (
|
| + image_name, self.options.build_revision)
|
| + self._UploadBitmapToCloudStorage(
|
| + base_bucket + '/ref', image_name_with_revision, ref_img, public=True)
|
| + self._UploadBitmapToCloudStorage(
|
| + base_bucket + '/gen', image_name_with_revision, screenshot,
|
| + public=True)
|
| + diff_img = screenshot.Diff(ref_img)
|
| + self._UploadBitmapToCloudStorage(
|
| + base_bucket + '/diff', image_name_with_revision, diff_img,
|
| + public=True)
|
| + print ('See http://%s.commondatastorage.googleapis.com/'
|
| + 'view_test_results.html?%s for this run\'s test results') % (
|
| + error_image_cloud_storage_bucket, upload_dir)
|
| +
|
| class Pixel(test.Test):
|
| test = PixelValidator
|
| page_set = 'page_sets/pixel_tests.json'
|
| @@ -164,6 +288,31 @@ class Pixel(test.Test):
|
| group.add_option('--build-revision',
|
| help='Chrome revision being tested.',
|
| default="unknownrev")
|
| + group.add_option('--upload-refimg-to-cloud-storage',
|
| + dest='upload_refimg_to_cloud_storage',
|
| + action='store_true', default=False,
|
| + help='Upload resulting images to cloud storage as reference images')
|
| + group.add_option('--download-refimg-from-cloud-storage',
|
| + dest='download_refimg_from_cloud_storage',
|
| + action='store_true', default=False,
|
| + help='Download reference images from cloud storage')
|
| + group.add_option('--refimg-cloud-storage-bucket',
|
| + help='Name of the cloud storage bucket to use for reference images; '
|
| + 'required with --upload-refimg-to-cloud-storage and '
|
| + '--download-refimg-from-cloud-storage. Example: '
|
| + '"chromium-gpu-archive/reference-images"')
|
| + group.add_option('--os-type',
|
| + help='Type of operating system on which the pixel test is being run, '
|
| + 'used only to distinguish different operating systems with the same '
|
| + 'graphics card. Any value is acceptable, but canonical values are '
|
| + '"win", "mac", and "linux", and probably, eventually, "chromeos" '
|
| + 'and "android").',
|
| + default='')
|
| + group.add_option('--test-machine-name',
|
| + help='Name of the test machine. Specifying this argument causes this '
|
| + 'script to upload failure images and diffs to cloud storage directly, '
|
| + 'instead of relying on the archive_gpu_pixel_test_results.py script.',
|
| + default='')
|
| parser.add_option_group(group)
|
|
|
| def CreatePageSet(self, options):
|
|
|