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