Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / test / gpu / gpu_tests / cloud_storage_test_base.py
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
3 # found in the LICENSE file.
4
5 """Base classes for a test and validator which upload results
6 (reference images, error images) to cloud storage."""
7
8 import os
9 import re
10 import tempfile
11
12 from telemetry import test
13 from telemetry.core import bitmap
14 from telemetry.page import cloud_storage
15 from telemetry.page import page_test
16
17 test_data_dir = os.path.abspath(os.path.join(
18     os.path.dirname(__file__), '..', '..', 'data', 'gpu'))
19
20 default_generated_data_dir = os.path.join(test_data_dir, 'generated')
21
22 error_image_cloud_storage_bucket = 'chromium-browser-gpu-tests'
23
24 class ValidatorBase(page_test.PageTest):
25   def __init__(self, test_method_name):
26     super(ValidatorBase, self).__init__(test_method_name)
27     # Parameters for cloud storage reference images.
28     self.vendor_id = None
29     self.device_id = None
30     self.vendor_string = None
31     self.device_string = None
32     self.msaa = False
33
34   ###
35   ### Routines working with the local disk (only used for local
36   ### testing without a cloud storage account -- the bots do not use
37   ### this code path).
38   ###
39
40   def _UrlToImageName(self, url):
41     image_name = re.sub(r'^(http|https|file)://(/*)', '', url)
42     image_name = re.sub(r'\.\./', '', image_name)
43     image_name = re.sub(r'(\.|/|-)', '_', image_name)
44     return image_name
45
46   def _WriteImage(self, image_path, png_image):
47     output_dir = os.path.dirname(image_path)
48     if not os.path.exists(output_dir):
49       os.makedirs(output_dir)
50     png_image.WritePngFile(image_path)
51
52   def _WriteErrorImages(self, img_dir, img_name, screenshot, ref_png):
53     full_image_name = img_name + '_' + str(self.options.build_revision)
54     full_image_name = full_image_name + '.png'
55
56     # Always write the failing image.
57     self._WriteImage(
58         os.path.join(img_dir, 'FAIL_' + full_image_name), screenshot)
59
60     if ref_png:
61       # Save the reference image.
62       # This ensures that we get the right revision number.
63       self._WriteImage(
64           os.path.join(img_dir, full_image_name), ref_png)
65
66       # Save the difference image.
67       diff_png = screenshot.Diff(ref_png)
68       self._WriteImage(
69           os.path.join(img_dir, 'DIFF_' + full_image_name), diff_png)
70
71   ###
72   ### Cloud storage code path -- the bots use this.
73   ###
74
75   def _ComputeGpuInfo(self, tab):
76     if ((self.vendor_id and self.device_id) or
77         (self.vendor_string and self.device_string)):
78       return
79     browser = tab.browser
80     if not browser.supports_system_info:
81       raise Exception('System info must be supported by the browser')
82     system_info = browser.GetSystemInfo()
83     if not system_info.gpu:
84       raise Exception('GPU information was absent')
85     device = system_info.gpu.devices[0]
86     if device.vendor_id and device.device_id:
87       self.vendor_id = device.vendor_id
88       self.device_id = device.device_id
89     elif device.vendor_string and device.device_string:
90       self.vendor_string = device.vendor_string
91       self.device_string = device.device_string
92     else:
93       raise Exception('GPU device information was incomplete')
94     self.msaa = not (
95         'disable_multisampling' in system_info.gpu.driver_bug_workarounds)
96
97   def _FormatGpuInfo(self, tab):
98     self._ComputeGpuInfo(tab)
99     msaa_string = '_msaa' if self.msaa else '_non_msaa'
100     if self.vendor_id:
101       return '%s_%04x_%04x%s' % (
102         self.options.os_type, self.vendor_id, self.device_id, msaa_string)
103     else:
104       return '%s_%s_%s%s' % (
105         self.options.os_type, self.vendor_string, self.device_string,
106         msaa_string)
107
108   def _FormatReferenceImageName(self, img_name, page, tab):
109     return '%s_v%s_%s.png' % (
110       img_name,
111       page.revision,
112       self._FormatGpuInfo(tab))
113
114   def _UploadBitmapToCloudStorage(self, bucket, name, bitmap, public=False):
115     # This sequence of steps works on all platforms to write a temporary
116     # PNG to disk, following the pattern in bitmap_unittest.py. The key to
117     # avoiding PermissionErrors seems to be to not actually try to write to
118     # the temporary file object, but to re-open its name for all operations.
119     temp_file = tempfile.NamedTemporaryFile().name
120     bitmap.WritePngFile(temp_file)
121     cloud_storage.Insert(bucket, name, temp_file, publicly_readable=public)
122
123   def _ConditionallyUploadToCloudStorage(self, img_name, page, tab, screenshot):
124     """Uploads the screenshot to cloud storage as the reference image
125     for this test, unless it already exists. Returns True if the
126     upload was actually performed."""
127     if not self.options.refimg_cloud_storage_bucket:
128       raise Exception('--refimg-cloud-storage-bucket argument is required')
129     cloud_name = self._FormatReferenceImageName(img_name, page, tab)
130     if not cloud_storage.Exists(self.options.refimg_cloud_storage_bucket,
131                                 cloud_name):
132       self._UploadBitmapToCloudStorage(self.options.refimg_cloud_storage_bucket,
133                                        cloud_name,
134                                        screenshot)
135       return True
136     return False
137
138   def _DownloadFromCloudStorage(self, img_name, page, tab):
139     """Downloads the reference image for the given test from cloud
140     storage, returning it as a Telemetry Bitmap object."""
141     # TODO(kbr): there's a race condition between the deletion of the
142     # temporary file and gsutil's overwriting it.
143     if not self.options.refimg_cloud_storage_bucket:
144       raise Exception('--refimg-cloud-storage-bucket argument is required')
145     temp_file = tempfile.NamedTemporaryFile().name
146     cloud_storage.Get(self.options.refimg_cloud_storage_bucket,
147                       self._FormatReferenceImageName(img_name, page, tab),
148                       temp_file)
149     return bitmap.Bitmap.FromPngFile(temp_file)
150
151   def _UploadErrorImagesToCloudStorage(self, image_name, screenshot, ref_img):
152     """For a failing run, uploads the failing image, reference image (if
153     supplied), and diff image (if reference image was supplied) to cloud
154     storage. This subsumes the functionality of the
155     archive_gpu_pixel_test_results.py script."""
156     machine_name = re.sub('\W+', '_', self.options.test_machine_name)
157     upload_dir = '%s_%s_telemetry' % (self.options.build_revision, machine_name)
158     base_bucket = '%s/runs/%s' % (error_image_cloud_storage_bucket, upload_dir)
159     image_name_with_revision = '%s_%s.png' % (
160       image_name, self.options.build_revision)
161     self._UploadBitmapToCloudStorage(
162       base_bucket + '/gen', image_name_with_revision, screenshot,
163       public=True)
164     if ref_img:
165       self._UploadBitmapToCloudStorage(
166         base_bucket + '/ref', image_name_with_revision, ref_img, public=True)
167       diff_img = screenshot.Diff(ref_img)
168       self._UploadBitmapToCloudStorage(
169         base_bucket + '/diff', image_name_with_revision, diff_img,
170         public=True)
171     print ('See http://%s.commondatastorage.googleapis.com/'
172            'view_test_results.html?%s for this run\'s test results') % (
173       error_image_cloud_storage_bucket, upload_dir)
174
175 class TestBase(test.Test):
176   @staticmethod
177   def _AddTestCommandLineOptions(parser, option_group):
178     option_group.add_option('--build-revision',
179         help='Chrome revision being tested.',
180         default="unknownrev")
181     option_group.add_option('--upload-refimg-to-cloud-storage',
182         dest='upload_refimg_to_cloud_storage',
183         action='store_true', default=False,
184         help='Upload resulting images to cloud storage as reference images')
185     option_group.add_option('--download-refimg-from-cloud-storage',
186         dest='download_refimg_from_cloud_storage',
187         action='store_true', default=False,
188         help='Download reference images from cloud storage')
189     option_group.add_option('--refimg-cloud-storage-bucket',
190         help='Name of the cloud storage bucket to use for reference images; '
191         'required with --upload-refimg-to-cloud-storage and '
192         '--download-refimg-from-cloud-storage. Example: '
193         '"chromium-gpu-archive/reference-images"')
194     option_group.add_option('--os-type',
195         help='Type of operating system on which the pixel test is being run, '
196         'used only to distinguish different operating systems with the same '
197         'graphics card. Any value is acceptable, but canonical values are '
198         '"win", "mac", and "linux", and probably, eventually, "chromeos" '
199         'and "android").',
200         default='')
201     option_group.add_option('--test-machine-name',
202         help='Name of the test machine. Specifying this argument causes this '
203         'script to upload failure images and diffs to cloud storage directly, '
204         'instead of relying on the archive_gpu_pixel_test_results.py script.',
205         default='')
206     option_group.add_option('--generated-dir',
207         help='Overrides the default on-disk location for generated test images '
208         '(only used for local testing without a cloud storage account)',
209         default=default_generated_data_dir)