| OLD | NEW |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """A cron job which queues old tests for deletion.""" | 5 """A cron job which queues old tests for deletion.""" |
| 6 | 6 |
| 7 import datetime | 7 import datetime |
| 8 import logging |
| 8 | 9 |
| 9 from google.appengine.api import taskqueue | 10 from google.appengine.api import taskqueue |
| 10 from google.appengine.datastore import datastore_query | 11 from google.appengine.datastore import datastore_query |
| 11 | 12 |
| 12 from dashboard import datastore_hooks | 13 from dashboard import datastore_hooks |
| 13 from dashboard import list_tests | 14 from dashboard import list_tests |
| 14 from dashboard import request_handler | 15 from dashboard import request_handler |
| 15 from dashboard import utils | 16 from dashboard import utils |
| 16 from dashboard.models import graph_data | 17 from dashboard.models import graph_data |
| 17 | 18 |
| 18 _CUTOFF_DATE = datetime.timedelta(days=183) # Six months ago | 19 _CUTOFF_DATE = datetime.timedelta(days=183) # Six months ago |
| 19 _TESTS_TO_CHECK_AT_ONCE = 100 | 20 _TESTS_TO_CHECK_AT_ONCE = 100 |
| 20 | 21 |
| 21 # Queue name needs to be listed in queue.yaml. | 22 # Queue name needs to be listed in queue.yaml. |
| 22 _TASK_QUEUE_NAME = 'delete-old-tests-queue' | 23 _TASK_QUEUE_NAME = 'delete-old-tests-queue' |
| 23 _DELETE_TASK_QUEUE_NAME = 'delete-tests-queue' | 24 _DELETE_TASK_QUEUE_NAME = 'delete-tests-queue' |
| 24 | 25 |
| 25 | 26 |
| 26 class DeleteOldTestsHandler(request_handler.RequestHandler): | 27 class DeleteOldTestsHandler(request_handler.RequestHandler): |
| 27 """Finds tests with no new data, and deletes them.""" | 28 """Finds tests with no new data, and deletes them.""" |
| 28 | 29 |
| 30 def get(self): |
| 31 self.post() |
| 32 |
| 29 def post(self): | 33 def post(self): |
| 30 """Query for tests, and put ones with no new data on the delete queue.""" | 34 """Query for tests, and put ones with no new data on the delete queue.""" |
| 31 datastore_hooks.SetPrivilegedRequest() | 35 datastore_hooks.SetPrivilegedRequest() |
| 36 logging.info('Cursor: %s', self.request.get('cursor')) |
| 32 cursor = datastore_query.Cursor(urlsafe=self.request.get('cursor')) | 37 cursor = datastore_query.Cursor(urlsafe=self.request.get('cursor')) |
| 33 tests, next_cursor, more = graph_data.TestMetadata.query().fetch_page( | 38 tests, next_cursor, more = graph_data.TestMetadata.query().fetch_page( |
| 34 _TESTS_TO_CHECK_AT_ONCE, keys_only=True, start_cursor=cursor) | 39 _TESTS_TO_CHECK_AT_ONCE, keys_only=True, start_cursor=cursor) |
| 35 if more: | |
| 36 taskqueue.add( | |
| 37 url='/delete_old_tests', | |
| 38 params={'cursor': next_cursor.urlsafe()}, | |
| 39 queue_name=_TASK_QUEUE_NAME) | |
| 40 for test in tests: | 40 for test in tests: |
| 41 # Delete this test if: | 41 # Delete this test if: |
| 42 # 1) It has no Rows newer than the cutoff | 42 # 1) It has no Rows newer than the cutoff |
| 43 # 2) It has no descendant tests | 43 # 2) It has no descendant tests |
| 44 logging.info('Checking %s', utils.TestPath(test)) |
| 44 no_new_rows = False | 45 no_new_rows = False |
| 45 last_row = graph_data.Row.query( | 46 last_row = graph_data.Row.query( |
| 46 graph_data.Row.parent_test == utils.OldStyleTestKey(test)).order( | 47 graph_data.Row.parent_test == utils.OldStyleTestKey(test)).order( |
| 47 -graph_data.Row.timestamp).get() | 48 -graph_data.Row.timestamp).get() |
| 48 if last_row: | 49 if last_row: |
| 49 if last_row.timestamp < datetime.datetime.today() - _CUTOFF_DATE: | 50 if last_row.timestamp < datetime.datetime.today() - _CUTOFF_DATE: |
| 50 no_new_rows = True | 51 no_new_rows = True |
| 51 else: | 52 else: |
| 52 no_new_rows = True | 53 no_new_rows = True |
| 53 descendants = list_tests.GetTestDescendants(test, keys_only=True) | 54 descendants = list_tests.GetTestDescendants(test, keys_only=True) |
| 54 descendants.remove(test) | 55 if test in descendants: |
| 56 descendants.remove(test) |
| 57 stamp = 'never' |
| 58 if last_row: |
| 59 stamp = last_row.timestamp |
| 55 if not descendants and no_new_rows: | 60 if not descendants and no_new_rows: |
| 61 logging.info('Deleting test %s last timestamp %s', |
| 62 utils.TestPath(test), stamp) |
| 56 taskqueue.add( | 63 taskqueue.add( |
| 57 url='/delete_test_data', | 64 url='/delete_test_data', |
| 58 params={ | 65 params={ |
| 59 'test_path': utils.TestPath(test), # For manual inspection. | 66 'test_path': utils.TestPath(test), # For manual inspection. |
| 60 'test_key': test.urlsafe(), | 67 'test_key': test.urlsafe(), |
| 61 }, | 68 }, |
| 62 queue_name=_DELETE_TASK_QUEUE_NAME) | 69 queue_name=_DELETE_TASK_QUEUE_NAME) |
| 70 else: |
| 71 logging.info('NOT Deleting test %s last timestamp %s', |
| 72 utils.TestPath(test), stamp) |
| 73 |
| 74 if more: |
| 75 taskqueue.add( |
| 76 url='/delete_old_tests', |
| 77 params={'cursor': next_cursor.urlsafe()}, |
| 78 queue_name=_TASK_QUEUE_NAME) |
| OLD | NEW |