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