Beispiel #1
0
    def test_response_time(self):
        """Tests that the response time we passed is returned."""
        http_metrics = metrics_utils.extract_http_metrics('', '', 0, 0.25)
        self.assertEqual(0.25, http_metrics['response_time'])

        http_metrics = metrics_utils.extract_http_metrics('', '', 0, 12345.25)
        self.assertEqual(12345.25, http_metrics['response_time'])
Beispiel #2
0
  def test_extracts_path_changes(self):
    """Tests that we extract paths for /changes/."""
    # /changes/<change-id>
    http_metrics = metrics_utils.extract_http_metrics(
        'https://review.example.com/changes/proj%2Fsrc%7Emaster%7EI1234abcd',
        '', 0, 0)
    self.assertEqual('changes', http_metrics['path'])

    # /changes/?q=<something>
    http_metrics = metrics_utils.extract_http_metrics(
        'https://review.example.com/changes/?q=owner:me+OR+cc:me',
        '', 0, 0)
    self.assertEqual('changes', http_metrics['path'])

    # /changes/#<something>
    http_metrics = metrics_utils.extract_http_metrics(
        'https://review.example.com/changes/#something',
        '', 0, 0)
    self.assertEqual('changes', http_metrics['path'])

    # /changes/<change-id>/<anything> does not map to changes.
    http_metrics = metrics_utils.extract_http_metrics(
        'https://review.example.com/changes/12345678/message',
        '', 0, 0)
    self.assertNotEqual('changes', http_metrics['path'])
Beispiel #3
0
    def test_status(self):
        """Tests that the response status we passed is returned."""
        http_metrics = metrics_utils.extract_http_metrics('', '', 123, 0)
        self.assertEqual(123, http_metrics['status'])

        http_metrics = metrics_utils.extract_http_metrics('', '', 404, 0)
        self.assertEqual(404, http_metrics['status'])
Beispiel #4
0
    def test_validates_method(self):
        """Test that we validate the HTTP method used."""
        # Regular case
        http_metrics = metrics_utils.extract_http_metrics('', 'POST', 0, 0)
        self.assertEqual('POST', http_metrics['method'])

        # Unexpected method is not reported
        http_metrics = metrics_utils.extract_http_metrics('', 'DEMAND', 0, 0)
        self.assertNotIn('method', http_metrics)
Beispiel #5
0
  def test_extracts_host(self):
    """Test that we extract the host from the requested URI."""
    # Regular case
    http_metrics = metrics_utils.extract_http_metrics(
        'https://chromium-review.googlesource.com/foo/bar?q=baz', '', 0, 0)
    self.assertEqual('chromium-review.googlesource.com', http_metrics['host'])

    # Unexpected host
    http_metrics = metrics_utils.extract_http_metrics(
        'https://foo-review.googlesource.com/', '', 0, 0)
    self.assertNotIn('host', http_metrics)
Beispiel #6
0
  def test_extracts_path(self):
    """Test that we extract the matching path from the requested URI."""
    # Regular case
    http_metrics = metrics_utils.extract_http_metrics(
        'https://review.example.com/changes/1234/revisions/deadbeef/commit',
        '', 0, 0)
    self.assertEqual('changes/revisions/commit', http_metrics['path'])

    # No matching paths
    http_metrics = metrics_utils.extract_http_metrics(
        'https://review.example.com/changes/1234/unexpected/path', '', 0, 0)
    self.assertNotIn('path', http_metrics)
Beispiel #7
0
  def test_extracts_arguments(self):
    """Test that we can extract arguments from the requested URI."""
    # Regular case
    http_metrics = metrics_utils.extract_http_metrics(
        'https://review.example.com/?q=123&foo=bar&o=ALL_REVISIONS', '', 0, 0)
    self.assertEqual(['ALL_REVISIONS'], http_metrics['arguments'])

    # Some unexpected arguments are filtered out.
    http_metrics = metrics_utils.extract_http_metrics(
        'https://review.example.com/?o=ALL_REVISIONS&o=LABELS&o=UNEXPECTED',
        '', 0, 0)
    self.assertEqual(['ALL_REVISIONS', 'LABELS'], http_metrics['arguments'])

    # No valid arguments, so arguments is not present
    http_metrics = metrics_utils.extract_http_metrics(
        'https://review.example.com/?o=bar&baz=1', '', 0, 0)
    self.assertNotIn('arguments', http_metrics)

    # No valid arguments, so arguments is not present
    http_metrics = metrics_utils.extract_http_metrics(
        'https://review.example.com/?foo=bar&baz=1', '', 0, 0)
    self.assertNotIn('arguments', http_metrics)
Beispiel #8
0
def ReadHttpResponse(conn, accept_statuses=frozenset([200])):
  """Reads an HTTP response from a connection into a string buffer.

  Args:
    conn: An Http object created by CreateHttpConn above.
    accept_statuses: Treat any of these statuses as success. Default: [200]
                     Common additions include 204, 400, and 404.
  Returns: A string buffer containing the connection's reply.
  """
  sleep_time = 1.5
  for idx in range(TRY_LIMIT):
    before_response = time.time()
    response, contents = conn.request(**conn.req_params)
    contents = contents.decode('utf-8', 'replace')

    response_time = time.time() - before_response
    metrics.collector.add_repeated(
        'http_requests',
        metrics_utils.extract_http_metrics(
            conn.req_params['uri'], conn.req_params['method'], response.status,
            response_time))

    # If response.status is an accepted status,
    # or response.status < 500 then the result is final; break retry loop.
    # If the response is 404/409 it might be because of replication lag,
    # so keep trying anyway.
    if (response.status in accept_statuses
        or response.status < 500 and response.status not in [404, 409]):
      LOGGER.debug('got response %d for %s %s', response.status,
                   conn.req_params['method'], conn.req_params['uri'])
      # If 404 was in accept_statuses, then it's expected that the file might
      # not exist, so don't return the gitiles error page because that's not
      # the "content" that was actually requested.
      if response.status == 404:
        contents = ''
      break

    # A status >=500 is assumed to be a possible transient error; retry.
    http_version = 'HTTP/%s' % ('1.1' if response.version == 11 else '1.0')
    LOGGER.warn('A transient error occurred while querying %s:\n'
                '%s %s %s\n'
                '%s %d %s',
                conn.req_host, conn.req_params['method'],
                conn.req_params['uri'],
                http_version, http_version, response.status, response.reason)

    if idx < TRY_LIMIT - 1:
      LOGGER.info('Will retry in %d seconds (%d more times)...',
                  sleep_time, TRY_LIMIT - idx - 1)
      time_sleep(sleep_time)
      sleep_time = sleep_time * 2
  # end of retries loop

  if response.status in accept_statuses:
    return StringIO(contents)

  if response.status in (302, 401, 403):
    www_authenticate = response.get('www-authenticate')
    if not www_authenticate:
      print('Your Gerrit credentials might be misconfigured.')
    else:
      auth_match = re.search('realm="([^"]+)"', www_authenticate, re.I)
      host = auth_match.group(1) if auth_match else conn.req_host
      print('Authentication failed. Please make sure your .gitcookies '
            'file has credentials for %s.' % host)
    print('Try:\n  git cl creds-check')

  reason = '%s: %s' % (response.reason, contents)
  raise GerritError(response.status, reason)
Beispiel #9
0
def ReadHttpResponse(conn, accept_statuses=frozenset([200])):
    """Reads an HTTP response from a connection into a string buffer.

  Args:
    conn: An Http object created by CreateHttpConn above.
    accept_statuses: Treat any of these statuses as success. Default: [200]
                     Common additions include 204, 400, and 404.
  Returns: A string buffer containing the connection's reply.
  """
    sleep_time = 1.5
    for idx in range(TRY_LIMIT):
        before_response = time.time()
        response, contents = conn.request(**conn.req_params)

        response_time = time.time() - before_response
        metrics.collector.add_repeated(
            'http_requests',
            metrics_utils.extract_http_metrics(conn.req_params['uri'],
                                               conn.req_params['method'],
                                               response.status, response_time))

        # Check if this is an authentication issue.
        www_authenticate = response.get('www-authenticate')
        if (response.status in (httplib.UNAUTHORIZED, httplib.FOUND)
                and www_authenticate):
            auth_match = re.search('realm="([^"]+)"', www_authenticate, re.I)
            host = auth_match.group(1) if auth_match else conn.req_host
            reason = (
                'Authentication failed. Please make sure your .gitcookies file '
                'has credentials for %s' % host)
            raise GerritAuthenticationError(response.status, reason)

        # If response.status < 500 then the result is final; break retry loop.
        # If the response is 404/409, it might be because of replication lag, so
        # keep trying anyway.
        if ((response.status < 500 and response.status not in [404, 409])
                or response.status in accept_statuses):
            LOGGER.debug('got response %d for %s %s', response.status,
                         conn.req_params['method'], conn.req_params['uri'])
            # If 404 was in accept_statuses, then it's expected that the file might
            # not exist, so don't return the gitiles error page because that's not
            # the "content" that was actually requested.
            if response.status == 404:
                contents = ''
            break
        # A status >=500 is assumed to be a possible transient error; retry.
        http_version = 'HTTP/%s' % ('1.1' if response.version == 11 else '1.0')
        LOGGER.warn(
            'A transient error occurred while querying %s:\n'
            '%s %s %s\n'
            '%s %d %s', conn.req_host, conn.req_params['method'],
            conn.req_params['uri'], http_version, http_version,
            response.status, response.reason)
        if response.status == 404:
            # TODO(crbug/881860): remove this hack.
            # HACK: try different Gerrit mirror as a workaround for potentially
            # out-of-date mirror hit through default routing.
            if conn.req_host == 'chromium-review.googlesource.com':
                conn.req_params['uri'] = _UseGerritMirror(
                    conn.req_params['uri'], 'chromium-review.googlesource.com')
                # And don't increase sleep_time in this case, since we suspect we've
                # just asked wrong git mirror before.
                sleep_time /= 2.0

        if TRY_LIMIT - idx > 1:
            LOGGER.info('Will retry in %d seconds (%d more times)...',
                        sleep_time, TRY_LIMIT - idx - 1)
            time.sleep(sleep_time)
            sleep_time = sleep_time * 2
    # end of retries loop
    if response.status not in accept_statuses:
        if response.status in (401, 403):
            print('Your Gerrit credentials might be misconfigured. Try: \n'
                  '  git cl creds-check')
        reason = '%s: %s' % (response.reason, contents)
        raise GerritError(response.status, reason)
    return StringIO(contents)