# Copyright 2013 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Module containing utility functions for reporting results."""

import logging
import os
import re

from pylib import constants
from pylib.results.flakiness_dashboard import results_uploader
from pylib.utils import logging_utils


def _LogToFile(results, test_type, suite_name):
    """Log results to local files which can be used for aggregation later."""
    log_file_path = os.path.join(constants.GetOutDirectory(), 'test_logs')
    if not os.path.exists(log_file_path):
        os.mkdir(log_file_path)
    full_file_name = os.path.join(
        log_file_path, re.sub(r'\W', '_', test_type).lower() + '.log'
    )
    if not os.path.exists(full_file_name):
        with open(full_file_name, 'w') as log_file:
            print(
                '\n%s results for %s build %s:'
                % (
                    test_type,
                    os.environ.get('BUILDBOT_BUILDERNAME'),
                    os.environ.get('BUILDBOT_BUILDNUMBER'),
                ),
                file=log_file,
            )
        logging.info('Writing results to %s.', full_file_name)

    logging.info('Writing results to %s.', full_file_name)
    with open(full_file_name, 'a') as log_file:
        shortened_suite_name = suite_name[:25] + (suite_name[25:] and '...')
        print(
            '%s%s' % (shortened_suite_name.ljust(30), results.GetShortForm()),
            file=log_file,
        )


def _LogToFlakinessDashboard(
    results, test_type, test_package, flakiness_server
):
    """Upload results to the flakiness dashboard"""
    logging.info(
        'Upload results for test type "%s", test package "%s" to %s',
        test_type,
        test_package,
        flakiness_server,
    )

    try:
        # TODO(jbudorick): remove Instrumentation once instrumentation tests
        # switch to platform mode.
        if test_type in ('instrumentation', 'Instrumentation'):
            if flakiness_server == constants.UPSTREAM_FLAKINESS_SERVER:
                assert test_package in [
                    'ContentShellTest',
                    'ChromePublicTest',
                    'ChromeSyncShellTest',
                    'SystemWebViewShellLayoutTest',
                    'WebViewInstrumentationTest',
                ]
                dashboard_test_type = (
                    '%s_instrumentation_tests'
                    % test_package.lower().rstrip('test')
                )
            # Downstream server.
            else:
                dashboard_test_type = 'Chromium_Android_Instrumentation'

        elif test_type == 'gtest':
            dashboard_test_type = test_package

        else:
            logging.warning('Invalid test type')
            return

        results_uploader.Upload(results, flakiness_server, dashboard_test_type)

    except Exception:  # pylint: disable=broad-except
        logging.exception('Failure while logging to %s', flakiness_server)


def LogFull(
    results,
    test_type,
    test_package,
    annotation=None,
    flakiness_server=None,
    quiet=False,
):
    """Log the tests results for the test suite.

    The results will be logged three different ways:
      1. Log to stdout.
      2. Log to local files for aggregating multiple test steps
         (on buildbots only).
      3. Log to flakiness dashboard (on buildbots only).

    Args:
      results: An instance of TestRunResults object.
      test_type: Type of the test (e.g. 'Instrumentation', 'Unit test', etc.).
      test_package: Test package name (e.g. 'ipc_tests' for gtests,
                    'ContentShellTest' for instrumentation tests)
      annotation: If instrumenation test type, this is a list of annotations
                  (e.g. ['Feature', 'SmallTest']).
      flakiness_server: If provider, upload the results to flakiness dashboard
                        with this URL.
    """
    # pylint doesn't like how colorama set up its color enums.
    # pylint: disable=no-member
    if not results.DidRunPass() and not quiet:
        logging.critical('*' * 80)
        logging.critical('Detailed Logs')
        logging.critical('*' * 80)
        for line in results.GetLogs().splitlines():
            logging.critical(line)
    logging.critical('*' * 80)
    logging.critical('Summary')
    logging.critical('*' * 80)

    colored_failed = logging_utils.Colorize('FAILED', logging_utils.FORE.RED)
    colored_passed = logging_utils.Colorize('PASSED', logging_utils.FORE.GREEN)
    for line in results.GetGtestForm().splitlines():
        line = line.replace('FAILED', colored_failed)
        line = line.replace('PASSED', colored_passed)
        logging.critical(line)
    logging.critical('*' * 80)

    if os.environ.get('BUILDBOT_BUILDERNAME'):
        # It is possible to have multiple buildbot steps for the same
        # instrumenation test package using different annotations.
        if annotation and len(annotation) == 1:
            suite_name = annotation[0]
        else:
            suite_name = test_package
        _LogToFile(results, test_type, suite_name)

        if flakiness_server:
            _LogToFlakinessDashboard(
                results, test_type, test_package, flakiness_server
            )
