• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"""The datastore model for alerts when data is no longer received for a test."""
6
7import logging
8
9from google.appengine.ext import ndb
10
11from dashboard import utils
12from dashboard.models import alert
13from dashboard.models import alert_group
14
15_MAX_GROUP_SIZE = 20
16
17
18class StoppageAlert(alert.Alert):
19  """A stoppage alert is an alert for a test no longer receiving new points.
20
21  Each StoppageAlert is associated with one TestMetadata, so if a test suite
22  gets deprecated or renamed, there may be a set of related StoppageAlerts
23  created.
24
25  The key for a StoppageAlert is of the form:
26    [("StoppageAlertParent", <test_path>), ("StoppageAlert", <revision>)].
27
28  Thus, two StoppageAlert entities can not be created for the same stoppage
29  event.
30  """
31  # Whether a mail notification has been sent for this alert.
32  mail_sent = ndb.BooleanProperty(indexed=True, default=False)
33
34  # Whether new points have been received for the test after this alert.
35  recovered = ndb.BooleanProperty(indexed=True, default=False)
36
37  # Computed properties are treated like member variables, so they have
38  # lowercase names, even though they look like methods to pylint.
39  # pylint: disable=invalid-name
40
41  @ndb.ComputedProperty
42  def revision(self):
43    return self.key.id()
44
45  @ndb.ComputedProperty
46  def test(self):
47    return utils.TestKey(self.key.parent().string_id())
48
49  @ndb.ComputedProperty
50  def row(self):
51    test_container = utils.GetTestContainerKey(self.GetTestMetadataKey())
52    return ndb.Key('Row', self.revision, parent=test_container)
53
54  @ndb.ComputedProperty
55  def start_revision(self):
56    return self.revision
57
58  @ndb.ComputedProperty
59  def end_revision(self):
60    return self.revision
61
62  @ndb.ComputedProperty
63  def last_row_date(self):
64    row = self.row.get()
65    if not row:
66      logging.warning('No Row with key %s', self.row)
67      return None
68    return row.timestamp
69
70
71def GetStoppageAlert(test_path, revision):
72  """Gets a StoppageAlert entity if it already exists.
73
74  Args:
75    test_path: The test path string of the TestMetadata associated with the
76               alert.
77    revision: The ID of the last point before the stoppage.
78
79  Returns:
80    A StoppageAlert entity or None.
81  """
82  return ndb.Key(
83      'StoppageAlertParent', test_path, 'StoppageAlert', revision).get()
84
85
86def CreateStoppageAlert(test, row):
87  """Creates a new StoppageAlert entity.
88
89  Args:
90    test: A TestMetadata entity.
91    row: A Row entity; the last Row that was put before the stoppage.
92
93  Returns:
94    A new StoppageAlert entity which has not been put, or None,
95    if we don't want to create a new StoppageAlert.
96  """
97  new_alert = StoppageAlert(
98      parent=ndb.Key('StoppageAlertParent', test.test_path),
99      id=row.revision,
100      internal_only=test.internal_only,
101      sheriff=test.sheriff)
102  alert_group.GroupAlerts([new_alert], test.suite_name, 'StoppageAlert')
103  grouped_alert_keys = StoppageAlert.query(
104      StoppageAlert.group == new_alert.group).fetch(keys_only=True)
105  if len(grouped_alert_keys) >= _MAX_GROUP_SIZE:
106    # Too many stoppage alerts in this group; we don't want to put any more.
107    return None
108  test.stoppage_alert = new_alert.key
109  test.put()
110  return new_alert
111