Ejemplo n.º 1
0
def _IsAnomalyRecovered(anomaly_entity):
    """Checks whether an Anomaly has recovered.

  An Anomaly will be considered "recovered" if there's a change point in
  the series after the Anomaly with roughly equal magnitude and opposite
  direction.

  Args:
    anomaly_entity: The original regression Anomaly.

  Returns:
    True if the Anomaly should be marked as recovered, False otherwise.
  """
    test = anomaly_entity.test.get()
    if not test:
        logging.error('Test %s not found for Anomaly %s, deleting test.',
                      utils.TestPath(anomaly_entity.test), anomaly_entity)
        anomaly_entity.key.delete()
        return False
    config = anomaly_config.GetAnomalyConfigDict(test)
    max_num_rows = config.get('max_window_size',
                              find_anomalies.DEFAULT_NUM_POINTS)
    rows = [
        r for r in find_anomalies.GetRowsToAnalyze(test, max_num_rows)
        if r.revision > anomaly_entity.end_revision
    ]
    change_points = find_anomalies.FindChangePointsForTest(rows, config)
    delta_anomaly = (anomaly_entity.median_after_anomaly -
                     anomaly_entity.median_before_anomaly)
    for change in change_points:
        delta_change = change.median_after - change.median_before
        if (_IsOppositeDirection(delta_anomaly, delta_change)
                and _IsApproximatelyEqual(delta_anomaly, -delta_change)):
            logging.debug('Anomaly %s recovered; recovery change point %s.',
                          anomaly_entity.key, change.AsDict())
            return True
    return False
Ejemplo n.º 2
0
def _MigrateStoppageAlerts(old_parent_key, new_parent_key):
    """Copies the StoppageAlert entities from one test to another.

  Args:
    old_parent_key: Source TestMetadata entity key.
    new_parent_key: Destination TestMetadata entity key.

  Returns:
    A list of Future objects for StoppageAlert puts and deletes.
  """
    alerts_to_update = stoppage_alert.StoppageAlert.GetAlertsForTest(
        old_parent_key, limit=_MAX_DATASTORE_PUTS_PER_PUT_MULTI_CALL)
    if not alerts_to_update:
        return []
    futures = []
    for entity in alerts_to_update:
        new_entity = stoppage_alert.StoppageAlert(parent=ndb.Key(
            'StoppageAlertParent', utils.TestPath(new_parent_key)),
                                                  id=entity.key.id(),
                                                  mail_sent=entity.mail_sent,
                                                  recovered=entity.recovered)
        futures.append(entity.key.delete_async())
        futures.append(new_entity.put_async())
    return futures
Ejemplo n.º 3
0
 def testGet_WithValidTestPath_ShowsChart(self):
     test_key = self._AddSampleData()
     test_path = utils.TestPath(test_key)
     response = self.testapp.get('/debug_alert?test_path=%s' % test_path)
     self.assertIn('id="plot"', response.body)
Ejemplo n.º 4
0
 def testGet_WithBogusParameterNames_ParameterIgnored(self, simulate_mock):
     test_key = self._AddSampleData()
     response = self.testapp.get('/debug_alert?test_path=%s&config=%s' %
                                 (utils.TestPath(test_key), '{"foo":0.75}'))
     simulate_mock.assert_called_once_with(mock.ANY)
     self.assertNotIn('"foo"', response.body)
 def SuitePath(alert):
   path_parts = utils.TestPath(alert.test).split('/')
   return '%s/%s' % (path_parts[0], path_parts[2])
Ejemplo n.º 6
0
 def test_path(self):
     """Slash-separated list of key parts, 'master/bot/suite/chart/...'."""
     return utils.TestPath(self.key)
Ejemplo n.º 7
0
    def get(self):
        """Gets the page for viewing recently added points.

    Request parameters:
      pattern: A test path pattern with asterisk wildcards (optional).

    Outputs:
      A page showing recently added points.
    """
        # Construct a query for recently added Row entities.
        query = graph_data.Row.query()
        query = query.order(-graph_data.Row.timestamp)

        # If a maximum number of tests was specified, use it; fall back on default.
        try:
            max_tests = int(self.request.get('max_tests', _MAX_MATCHING_TESTS))
        except ValueError:
            max_tests = _MAX_MATCHING_TESTS

        # If a test path pattern was specified, filter the query to include only
        # Row entities that belong to a test that matches the pattern.
        test_pattern = self.request.get('pattern')
        num_originally_matching_tests = 0
        if test_pattern:
            test_paths = list_tests.GetTestsMatchingPattern(
                test_pattern, only_with_rows=True)
            if not test_paths:
                self.RenderHtml(
                    'new_points.html', {
                        'pattern': test_pattern,
                        'error':
                        'No tests matching pattern: %s' % test_pattern,
                    })
                return

            # If test_keys contains too many tests, then this query will exceed a
            # memory limit or time out. So, limit the number of tests and let the
            # user know that this has happened.
            num_originally_matching_tests = len(test_paths)
            if num_originally_matching_tests > max_tests:
                test_paths = test_paths[:max_tests]
            test_keys = map(utils.OldStyleTestKey, test_paths)
            query = query.filter(graph_data.Row.parent_test.IN(test_keys))

        # If a valid number of points was given, use it. Otherwise use the default.
        try:
            num_points = int(
                self.request.get('num_points', _DEFAULT_NUM_POINTS))
        except ValueError:
            num_points = _DEFAULT_NUM_POINTS

        # Fetch the Row entities.
        rows = query.fetch(limit=num_points)

        # Make a list of dicts which will be passed to the template.
        row_dicts = []
        for row in rows:
            row_dicts.append({
                'test':
                utils.TestPath(row.parent_test),
                'added_time':
                row.timestamp.strftime('%Y-%m-%d %H:%M:%S %Z'),
                'revision':
                row.revision,
                'value':
                row.value,
                'error':
                row.error,
            })

        error_message = ''
        if num_originally_matching_tests > max_tests:
            error_message = (
                'Pattern originally matched %s tests; only showing '
                'points from the first %s tests.' %
                (num_originally_matching_tests, max_tests))

        # Render the template with the row information that was fetched.
        self.RenderHtml(
            'new_points.html', {
                'pattern': test_pattern,
                'num_points': num_points,
                'max_tests': max_tests,
                'rows': row_dicts,
                'error': error_message,
            })
Ejemplo n.º 8
0
def _ListSubTestCacheKey(test_key):
    """Returns the sub-tests list cache key for a test suite."""
    parts = utils.TestPath(test_key).split('/')
    master, bot, suite = parts[0:3]
    return graph_data.LIST_TESTS_SUBTEST_CACHE_KEY % (master, bot, suite)
Ejemplo n.º 9
0
def _SubTestPath(test_key):
    """Returns the part of a test path starting from after the test suite."""
    full_test_path = utils.TestPath(test_key)
    parts = full_test_path.split('/')
    assert len(parts) > 3
    return '/'.join(parts[3:])
Ejemplo n.º 10
0
 def SuitePath(alert):
   path_parts = utils.TestPath(alert.GetTestMetadataKey()).split('/')
   return '%s/%s' % (path_parts[0], path_parts[2])
Ejemplo n.º 11
0
 def testGetTestMetadataKey_TestMetadata(self):
     a = anomaly.Anomaly(test=utils.TestKey('a/b/c/d'))
     k = a.GetTestMetadataKey()
     self.assertEqual('TestMetadata', k.kind())
     self.assertEqual('a/b/c/d', k.id())
     self.assertEqual('a/b/c/d', utils.TestPath(k))
Ejemplo n.º 12
0
def GetBotNamesFromAlerts(alerts):
    """Gets a set with the names of the bots related to some alerts."""
    # a.test is the key of a TestMetadata entity, and the TestPath is a path like
    # master_name/bot_name/test_suite_name/metric...
    return {utils.TestPath(a.test).split('/')[1] for a in alerts}
Ejemplo n.º 13
0
 def testTestPath_Container(self):
     key = ndb.Key('TestContainer', 'm/b/suite/metric')
     self.assertEqual('m/b/suite/metric', utils.TestPath(key))
Ejemplo n.º 14
0
 def testTestPath_TestMetadata(self):
     key = ndb.Key('TestMetadata', 'm/b/suite/metric')
     self.assertEqual('m/b/suite/metric', utils.TestPath(key))
Ejemplo n.º 15
0
 def testTestPath_Test(self):
     key = ndb.Key('Master', 'm', 'Bot', 'b', 'Test', 'suite', 'Test',
                   'metric')
     self.assertEqual('m/b/suite/metric', utils.TestPath(key))