1# Copyright 2015 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"""Provides a web interface for seeing recently added points.""" 6 7from dashboard import list_tests 8from dashboard import request_handler 9from dashboard import utils 10from dashboard.models import graph_data 11 12# Number of points to list if no number of points is specified. 13_DEFAULT_NUM_POINTS = 100 14 15# Max number of tests to use that match a user-specified pattern. 16_MAX_MATCHING_TESTS = 5 17 18 19class NewPointsHandler(request_handler.RequestHandler): 20 """Shows a page with a list of recently added points.""" 21 22 def get(self): 23 """Gets the page for viewing recently added points. 24 25 Request parameters: 26 pattern: A test path pattern with asterisk wildcards (optional). 27 28 Outputs: 29 A page showing recently added points. 30 """ 31 # Construct a query for recently added Row entities. 32 query = graph_data.Row.query() 33 query = query.order(-graph_data.Row.timestamp) 34 35 # If a maximum number of tests was specified, use it; fall back on default. 36 try: 37 max_tests = int(self.request.get('max_tests', _MAX_MATCHING_TESTS)) 38 except ValueError: 39 max_tests = _MAX_MATCHING_TESTS 40 41 # If a test path pattern was specified, filter the query to include only 42 # Row entities that belong to a test that matches the pattern. 43 test_pattern = self.request.get('pattern') 44 num_originally_matching_tests = 0 45 if test_pattern: 46 test_paths = list_tests.GetTestsMatchingPattern( 47 test_pattern, only_with_rows=True) 48 if not test_paths: 49 self.RenderHtml('new_points.html', { 50 'pattern': test_pattern, 51 'error': 'No tests matching pattern: %s' % test_pattern, 52 }) 53 return 54 55 # If test_keys contains too many tests, then this query will exceed a 56 # memory limit or time out. So, limit the number of tests and let the 57 # user know that this has happened. 58 num_originally_matching_tests = len(test_paths) 59 if num_originally_matching_tests > max_tests: 60 test_paths = test_paths[:max_tests] 61 test_keys = map(utils.OldStyleTestKey, test_paths) 62 query = query.filter(graph_data.Row.parent_test.IN(test_keys)) 63 64 # If a valid number of points was given, use it. Otherwise use the default. 65 try: 66 num_points = int(self.request.get('num_points', _DEFAULT_NUM_POINTS)) 67 except ValueError: 68 num_points = _DEFAULT_NUM_POINTS 69 70 # Fetch the Row entities. 71 rows = query.fetch(limit=num_points) 72 73 # Make a list of dicts which will be passed to the template. 74 row_dicts = [] 75 for row in rows: 76 row_dicts.append({ 77 'test': utils.TestPath(row.parent_test), 78 'added_time': row.timestamp.strftime('%Y-%m-%d %H:%M:%S %Z'), 79 'revision': row.revision, 80 'value': row.value, 81 'error': row.error, 82 }) 83 84 error_message = '' 85 if num_originally_matching_tests > max_tests: 86 error_message = ('Pattern originally matched %s tests; only showing ' 87 'points from the first %s tests.' % 88 (num_originally_matching_tests, max_tests)) 89 90 # Render the template with the row information that was fetched. 91 self.RenderHtml('new_points.html', { 92 'pattern': test_pattern, 93 'num_points': num_points, 94 'max_tests': max_tests, 95 'rows': row_dicts, 96 'error': error_message, 97 }) 98