Home | History | Annotate | Download | only in server
      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 """Request handler to serve the main_view page."""
      6 
      7 import jinja2
      8 import json
      9 import os
     10 import re
     11 import sys
     12 import webapp2
     13 
     14 import ispy_api
     15 from common import constants
     16 from common import ispy_utils
     17 
     18 import gs_bucket
     19 import views
     20 
     21 JINJA = jinja2.Environment(
     22     loader=jinja2.FileSystemLoader(os.path.dirname(views.__file__)),
     23     extensions=['jinja2.ext.autoescape'])
     24 
     25 
     26 class MainViewHandler(webapp2.RequestHandler):
     27   """Request handler to serve the main_view page."""
     28 
     29   def get(self):
     30     """Handles a get request to the main_view page.
     31 
     32     If the test_run parameter is specified, then a page displaying all of
     33     the failed runs in the test_run will be shown. Otherwise a view listing
     34     all of the test_runs available for viewing will be displayed.
     35     """
     36     test_run = self.request.get('test_run')
     37     bucket = gs_bucket.GoogleCloudStorageBucket(constants.BUCKET)
     38     ispy = ispy_utils.ISpyUtils(bucket)
     39     # Load the view.
     40     if test_run:
     41       self._GetForTestRun(test_run, ispy)
     42       return
     43     self._GetAllTestRuns(ispy)
     44 
     45   def _GetAllTestRuns(self, ispy):
     46     """Renders a list view of all of the test_runs available in GS.
     47 
     48     Args:
     49       ispy: An instance of ispy_api.ISpyApi.
     50     """
     51     template = JINJA.get_template('list_view.html')
     52     data = {}
     53     test_runs = set([path.lstrip('/').split('/')[1] for path in
     54                     ispy.GetAllPaths('failures/')])
     55     base_url = '/?test_run=%s'
     56     data['links'] = [(test_run, base_url % test_run) for test_run in test_runs]
     57     self.response.write(template.render(data))
     58 
     59   def _GetForTestRun(self, test_run, ispy):
     60     """Renders a sorted list of failure-rows for a given test_run.
     61 
     62     This method will produce a list of failure-rows that are sorted
     63     in descending order by number of different pixels.
     64 
     65     Args:
     66       test_run: The name of the test_run to render failure rows from.
     67       ispy: An instance of ispy_api.ISpyApi.
     68     """
     69     paths = set([path for path in ispy.GetAllPaths('failures/' + test_run)
     70                  if path.endswith('actual.png')])
     71     can_rebaseline = ispy_api.ISpyApi(
     72         ispy.cloud_bucket).CanRebaselineToTestRun(test_run)
     73     rows = [self._CreateRow(test_run, path, ispy) for path in paths]
     74 
     75     # Function that sorts by the different_pixels field in the failure-info.
     76     def _Sorter(a, b):
     77       return cmp(b['percent_different'],
     78                  a['percent_different'])
     79     template = JINJA.get_template('main_view.html')
     80     self.response.write(
     81         template.render({'comparisons': sorted(rows, _Sorter),
     82                          'test_run': test_run,
     83                          'can_rebaseline': can_rebaseline}))
     84 
     85   def _CreateRow(self, test_run, path, ispy):
     86     """Creates one failure-row.
     87 
     88     This method builds a dictionary with the data necessary to display a
     89     failure in the main_view html template.
     90 
     91     Args:
     92       test_run: The name of the test_run the failure is in.
     93       path: A path to the failure's actual.png file.
     94       ispy: An instance of ispy_api.ISpyApi.
     95 
     96     Returns:
     97       A dictionary with fields necessary to render a failure-row
     98         in the main_view html template.
     99     """
    100     res = {}
    101     res['expectation'] = path.lstrip('/').split('/')[2]
    102     res['test_run'] = test_run
    103     res['info'] = json.loads(ispy.cloud_bucket.DownloadFile(
    104         ispy_utils.GetFailurePath(res['test_run'], res['expectation'],
    105                                   'info.txt')))
    106     expected = ispy_utils.GetExpectationPath(
    107         res['expectation'], 'expected.png')
    108     diff = ispy_utils.GetFailurePath(test_run, res['expectation'], 'diff.png')
    109     res['percent_different'] = res['info']['fraction_different'] * 100
    110     res['expected_path'] = expected
    111     res['diff_path'] = diff
    112     res['actual_path'] = path
    113     res['expected'] = ispy.cloud_bucket.GetImageURL(expected)
    114     res['diff'] = ispy.cloud_bucket.GetImageURL(diff)
    115     res['actual'] = ispy.cloud_bucket.GetImageURL(path)
    116     return res
    117