Index: chrome/test/functional/ispy/ispy_core/Tools/bucket_manager.py |
diff --git a/chrome/test/functional/ispy/ispy_core/Tools/bucket_manager.py b/chrome/test/functional/ispy/ispy_core/Tools/bucket_manager.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..638cbe50be6f79ed53c5b910cc1b3a4aed38122f |
--- /dev/null |
+++ b/chrome/test/functional/ispy/ispy_core/Tools/bucket_manager.py |
@@ -0,0 +1,236 @@ |
+# Copyright (c) 2013 The Chromium Authos. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+"""Utilities for accessing data on Google Cloud Storage.""" |
+ |
+import StringIO |
+import sys |
+sys.path.append('gsutil/third_party/boto') |
+from PIL import Image |
+ |
+import image_tools |
+ |
+KEY = 'GOOGMLY23XF2KSSJ6WHF' |
+SECRET = 'YletkArpp6KSucfnz/kwfyCUnokm/MzJX3KeiB4Y' |
+BUCKET = 'i-spy' |
+ |
+ |
+class NotFoundException(Exception): |
+ pass |
+ |
+ |
+class Manager(object): |
+ """Responsible for handling bucket operations through a provided injector.""" |
+ |
+ def __init__(self, boto_injector): |
+ """Creates a bucket manager from a boto_injector. |
+ |
+ Args: |
+ bucket_injector: an instance of a class implementing |
+ Tools.BucketManagerTests.DependancyInjection.boto_injector. |
+ |
+ Returns: |
+ an instance of Tools.bucket_manager.Manager |
+ """ |
+ self.b = boto_injector |
+ self.bucket = self._GetConnection() |
+ |
+ def _AuthenticateBucket(self, bucket, key, secret): |
+ """Returns a connection to a given bucket. |
+ |
+ Args: |
+ bucket: The name of the bucket to be accessed. |
+ key: An access key for a cloudstorage project. |
+ secret: An access secret for a cloudstorage project. |
+ |
+ Returns: |
+ an instance of boto.gs.connection, which is an access point |
+ through which users can manipulate items in the given bucket. |
+ """ |
+ uri = self.b.storage_uri('', 'gs') |
+ conn = self.b.connect(uri, key, secret) |
+ return self.b.get_bucket(conn, bucket) |
+ |
+ def _GetConnection(self): |
+ """Returns a connection to the i-spy bucket. |
+ |
+ Returns: |
+ an instance of boto.gs.bucket that serves as an access point |
+ to the i-spy bucket. |
+ """ |
+ return self._AuthenticateBucket(BUCKET, KEY, SECRET) |
+ |
+ def MakeKeyToFile(self, path): |
+ """Returns a key to a file that may or may not be in the i-spy bucket. |
+ |
+ Args: |
+ path: the path to generate a key for. |
+ |
+ Returns: |
+ an instance of boto.gs.key which is an access point to a particular |
+ resource in the i-spy bucket. |
+ """ |
+ k = self.b.get_key(self.bucket) |
+ k.set_path(path) |
+ return k |
+ |
+ def GetKeyToFile(self, path): |
+ """Returns a key to a file that necessarily exists in the i-spy bucket. |
+ |
+ Args: |
+ path: the path to the file to be retrieved. |
+ |
+ Returns: |
+ an instance of boto.gs.key, which is an access point to a particular |
+ resource in the i-spy bucket. |
+ |
+ Raises: |
+ NotFoundException: if the file being queried could not be found. |
+ """ |
+ k = self.MakeKeyToFile(path) |
+ if k.exists(): |
+ return k |
+ else: |
+ raise NotFoundException('Could not get file.') |
+ |
+ def UploadImage(self, full_path, image): |
+ """Uploads an image to a specified path under the i-spy bucket. |
+ |
+ This function takes a path and image as input, then stores the |
+ data from the image in the provided path in the i-spy bucket. |
+ |
+ Args: |
+ full_path: the full path, including file extension, to where the |
+ image should be stored. |
+ image: the RGB image to be stored in the i-spy bucket. |
+ |
+ Returns: |
+ None. |
+ """ |
+ key = self.MakeKeyToFile(full_path) |
+ key.set_metadata('Content-Type', 'image/png') |
+ key.set_contents_from_string( |
+ image_tools.SerializeImage(image).decode('base64') |
+ ) |
+ |
+ def UploadTest(self, test_name, images): |
+ """Uploads a set of images as a test. |
+ |
+ This function uploads a collection of images which are |
+ accepted as being visually correct. A mask is then generated |
+ to account for the differences between the images. This mask |
+ will be used to occlude animated portions of the images in the |
+ test so they do not throw-off the pixel-by-pixel comparison. |
+ The mask is stored under /Tests/[test_name]_mask.png, and |
+ the color image is stored as /Tests/[test_name]_expected.png. |
+ |
+ Args: |
+ test_name: the name to give the newly created test |
+ images: a list of images that will be processed into a mask, |
+ and expected image. |
+ |
+ Returns: |
+ None. |
+ """ |
+ mask = image_tools.CreateMask(images) |
+ path = 'Tests/%s_%s.png' |
+ self.UploadImage(path % (test_name, 'mask'), mask) |
+ self.UploadImage(path % (test_name, 'expected'), images[0]) |
+ |
+ def UploadResult(self, test_name, run_name, expected, |
+ diff, actual): |
+ """Uploads an expected, a difference, and an actual image as a result. |
+ |
+ This function uploads a three images, expected, diff, and actual |
+ to the i-spy bucket under /Results/[test_name]_[expected/diff/actual].png. |
+ |
+ Args: |
+ test_name: the name of the test that this result corresponds to. |
+ run_name: the name of the particular run of the test to upload. |
+ expected: the correct RGB image provided by the test. |
+ diff: the difference between the correct RGB image and the image |
+ that the test has been run on. |
+ actual: the RGB image that the test was run on. |
+ |
+ Returns: |
+ None. |
+ """ |
+ path = 'Results/' + test_name + '/' + run_name + '/%s.png' |
+ self.UploadImage(path % 'expected', expected) |
+ self.UploadImage(path % 'diff', diff) |
+ self.UploadImage(path % 'actual', actual) |
+ |
+ def GetTest(self, test_name): |
+ """Returns a dictionary of the expected and mask images of a given test. |
+ |
+ Args: |
+ test_name: the name of the test to get. |
+ |
+ Returns: |
+ a dictionary of the expected, and mask RGB images of the test. |
+ |
+ Raises: |
+ NotFoundException: if the test being queried could not be found. |
+ """ |
+ mask_key = self.GetKeyToFile('Tests/%s_mask.png' % test_name) |
+ expected_key = self.GetKeyToFile('Tests/%s_expected.png' % test_name) |
+ return { |
+ 'expected': Image.open(StringIO.StringIO( |
+ expected_key.get_contents_as_string())), |
+ 'mask': Image.open(StringIO.StringIO( |
+ mask_key.get_contents_as_string())) |
+ } |
+ |
+ def GetResult(self, test_name, run_name): |
+ """Returns the Result of a particular run of a test. |
+ |
+ This function returns a dictionary of three keys: 'expected', |
+ 'diff', and 'actual' which are mapped to urls pointing to |
+ their respective images for the given result. |
+ |
+ Args: |
+ test_name: the name of the test to get a result from. |
+ run_name: the name of a particular run of the given test. |
+ |
+ Returns: |
+ a dictionary of strings mapped to url-strings for the 'expected', |
+ 'diff', and 'actual' components of a result. |
+ |
+ Raises: |
+ NotFoundException: if the result being queried could not be found. |
+ """ |
+ path = 'Results/%s/%s/' % (test_name, run_name) + '%s.png' |
+ return { |
+ 'expected': self.GetURL(path % 'expected'), |
+ 'diff': self.GetURL(path % 'diff'), |
+ 'actual': self.GetURL(path % 'actual') |
+ } |
+ |
+ def GetURL(self, full_path): |
+ """Returns the url to a file in the i-spy bucket. |
+ |
+ Args: |
+ full_path: the full path to the file. |
+ |
+ Returns: |
+ the url of the file as a string that will be valid for 5 minutes after |
+ the function call. |
+ |
+ Raises: |
+ NotFoundException: if full_path does not exist in the ispy bucket. |
+ """ |
+ key = self.GetKeyToFile(full_path) |
+ return key.generate_url(300).replace('AWSAccessKeyId', 'GoogleAccessId') |
+ |
+ def GetAllKeys(self, prefix=None): |
+ """Returns all keys in the i-spy bucket starting with a prefix. |
+ |
+ Args: |
+ prefix: An optional prefix to get all keys starting with. If the prefix |
+ is left empty, all keys in the bucket will be returned. |
+ |
+ Returns: |
+ a list of all the keys in the i-spy bucket. |
+ """ |
+ return self.b.get_all_keys(self.bucket, prefix) |