Home | History | Annotate | Download | only in rebaseline_server
      1 #!/usr/bin/python
      2 
      3 """
      4 Copyright 2014 Google Inc.
      5 
      6 Use of this source code is governed by a BSD-style license that can be
      7 found in the LICENSE file.
      8 
      9 ImagePair class (see class docstring for details)
     10 """
     11 
     12 import posixpath
     13 
     14 
     15 # Keys used within ImagePair dictionary representations.
     16 # NOTE: Keep these in sync with static/constants.js
     17 KEY__IMAGEPAIRS__DIFFERENCES = 'differenceData'
     18 KEY__IMAGEPAIRS__EXPECTATIONS = 'expectations'
     19 KEY__IMAGEPAIRS__EXTRACOLUMNS = 'extraColumns'
     20 KEY__IMAGEPAIRS__IMAGE_A_URL = 'imageAUrl'
     21 KEY__IMAGEPAIRS__IMAGE_B_URL = 'imageBUrl'
     22 KEY__IMAGEPAIRS__IS_DIFFERENT = 'isDifferent'
     23 
     24 
     25 class ImagePair(object):
     26   """Describes a pair of images, pixel difference info, and optional metadata.
     27   """
     28 
     29   def __init__(self, image_diff_db,
     30                base_url, imageA_relative_url, imageB_relative_url,
     31                expectations=None, extra_columns=None):
     32     """
     33     Args:
     34       image_diff_db: ImageDiffDB instance we use to generate/store image diffs
     35       base_url: base of all image URLs
     36       imageA_relative_url: string; URL pointing at an image, relative to
     37           base_url; or None, if this image is missing
     38       imageB_relative_url: string; URL pointing at an image, relative to
     39           base_url; or None, if this image is missing
     40       expectations: optional dictionary containing expectations-specific
     41           metadata (ignore-failure, bug numbers, etc.)
     42       extra_columns: optional dictionary containing more metadata (test name,
     43           builder name, etc.)
     44     """
     45     self.base_url = base_url
     46     self.imageA_relative_url = imageA_relative_url
     47     self.imageB_relative_url = imageB_relative_url
     48     self.expectations_dict = expectations
     49     self.extra_columns_dict = extra_columns
     50     if not imageA_relative_url or not imageB_relative_url:
     51       self._is_different = True
     52       self.diff_record = None
     53     elif imageA_relative_url == imageB_relative_url:
     54       self._is_different = False
     55       self.diff_record = None
     56     else:
     57       # TODO(epoger): Rather than blocking until image_diff_db can read in
     58       # the image pair and generate diffs, it would be better to do it
     59       # asynchronously: tell image_diff_db to download a bunch of file pairs,
     60       # and only block later if we're still waiting for diff_records to come
     61       # back.
     62       self._is_different = True
     63       image_diff_db.add_image_pair(
     64           expected_image_locator=imageA_relative_url,
     65           expected_image_url=posixpath.join(base_url, imageA_relative_url),
     66           actual_image_locator=imageB_relative_url,
     67           actual_image_url=posixpath.join(base_url, imageB_relative_url))
     68       self.diff_record = image_diff_db.get_diff_record(
     69           expected_image_locator=imageA_relative_url,
     70           actual_image_locator=imageB_relative_url)
     71       if self.diff_record and self.diff_record.get_num_pixels_differing() == 0:
     72         self._is_different = False
     73 
     74   def as_dict(self):
     75     """Returns a dictionary describing this ImagePair.
     76 
     77     Uses the KEY__IMAGEPAIRS__* constants as keys.
     78     """
     79     asdict = {
     80         KEY__IMAGEPAIRS__IMAGE_A_URL: self.imageA_relative_url,
     81         KEY__IMAGEPAIRS__IMAGE_B_URL: self.imageB_relative_url,
     82     }
     83     asdict[KEY__IMAGEPAIRS__IS_DIFFERENT] = self._is_different
     84     if self.expectations_dict:
     85       asdict[KEY__IMAGEPAIRS__EXPECTATIONS] = self.expectations_dict
     86     if self.extra_columns_dict:
     87       asdict[KEY__IMAGEPAIRS__EXTRACOLUMNS] = self.extra_columns_dict
     88     if self.diff_record and (self.diff_record.get_num_pixels_differing() > 0):
     89       asdict[KEY__IMAGEPAIRS__DIFFERENCES] = self.diff_record.as_dict()
     90     return asdict
     91