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 database models for anomaly alerting threshold configs."""
6
7import logging
8
9from google.appengine.ext import ndb
10
11# The parameters to use from anomaly threshold config dict.
12# Any parameters in such a dict that aren't in this list will be ignored.
13_VALID_ANOMALY_CONFIG_PARAMETERS = {
14    'max_window_size',
15    'min_segment_size',
16    'min_absolute_change',
17    'min_relative_change',
18    'min_steppiness',
19    'multiple_of_std_dev',
20}
21
22
23class AnomalyConfig(ndb.Model):
24  """Represents a set of parameters for the anomaly detection function.
25
26  The anomaly detection module uses set of parameters to determine the
27  thresholds for what is considered an anomaly.
28  """
29  # A dictionary mapping parameter names to values.
30  config = ndb.JsonProperty(required=True, indexed=False)
31
32  # A list of test path patterns. Each pattern is a string which can match parts
33  # of the test path either exactly, or use * as a wildcard.
34  # Note: Test entities contain a key property called overridden_anomaly_config,
35  # which is set in the pre-put hook for Test in graph_data.py.
36  patterns = ndb.StringProperty(repeated=True, indexed=False)
37
38
39def CleanConfigDict(config_dict):
40  """Removes invalid parameters from a config dictionary.
41
42  In the config dict there may be extra "comment" parameters which
43  should be ignored. These are removed so that the parameters can
44  be passed to FindChangePoints using ** notation.
45  """
46  return {key: value for key, value in config_dict.iteritems()
47          if key in _VALID_ANOMALY_CONFIG_PARAMETERS}
48
49
50def GetAnomalyConfigDict(test):
51  """Gets the anomaly threshold config for the given test.
52
53  Args:
54    test: Test entity to get the config for.
55
56  Returns:
57    A dictionary with threshold parameters for the given test.
58  """
59  if not test.overridden_anomaly_config:
60    return {}
61  anomaly_config = test.overridden_anomaly_config.get()
62  if not anomaly_config:
63    logging.warning('No AnomalyConfig fetched from key %s for test %s',
64                    test.overridden_anomaly_config, test.test_path)
65    # The the overridden_anomaly_config property should be reset
66    # in the pre-put hook of the Test entity.
67    test.put()
68    return {}
69  return CleanConfigDict(anomaly_config.config)
70