# Copyright 2021 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Full test of pw_presubmit module."""

import collections
import datetime

from PB.recipe_modules.pigweed.gerrit_comment.options import CommentBehavior
from PB.recipe_modules.pigweed.pw_presubmit.tests.full import InputProperties

DEPS = [
    'pigweed/checkout',
    'pigweed/pw_presubmit',
    'recipe_engine/json',
    'recipe_engine/path',
    'recipe_engine/properties',
    'recipe_engine/raw_io',
    'recipe_engine/time',
]

PROPERTIES = InputProperties

Environment = collections.namedtuple('Environment', 'override_gn_args')


def RunSteps(api, props):  # pylint: disable=invalid-name
    presubmit = api.pw_presubmit.init(
        api.path['start_dir'].join('checkout'), props.pw_presubmit_options,
    )

    log_dir = api.path['start_dir'].join('logs')

    for i, step in enumerate(presubmit.steps):
        # Need to take path with and without log_dir argument for coverage.
        kw = {}
        if i:
            kw['log_dir'] = log_dir.join(step.name)

        if i:
            kw['env'] = Environment(dict(foo=1))
        else:
            kw['env'] = Environment(dict(foo='bar'))

        api.pw_presubmit.run(presubmit, step, **kw)

    # For coverage.
    _ = api.pw_presubmit.build_id(presubmit)


def GenTests(api):  # pylint: disable=invalid-name
    """Create tests."""

    def properties(**kwargs):
        props = InputProperties(
            pw_presubmit_options=api.pw_presubmit.options(**kwargs),
        )
        return api.properties(props)

    yield (
        api.test('no-steps', status='FAILURE')
        + properties()
        + api.checkout.ci_test_data()
    )

    yield (
        api.test('bad-json-steps')
        + properties(program=['program'])
        + api.step_data(
            'get steps from programs.get steps', stdout=api.json.output(None),
        )
        + api.checkout.ci_test_data()
    )

    yield (
        api.test('empty-program')
        + properties(program=['empty'])
        + api.step_data(
            'get steps from programs.get steps', stdout=api.json.output([]),
        )
    )

    yield (
        api.test('substep', status='FAILURE')
        + properties(step=['composite'])
        + api.step_data(
            'get steps from programs.get steps',
            stdout=api.json.output(
                [
                    {
                        'name': 'composite',
                        'substeps': ['substep1', 'substep2', 'substep3'],
                    },
                ],
            ),
        )
        + api.step_data('composite.substep2', retcode=1)
    )

    yield (
        api.test('pigweed')
        + properties(
            command_name='foo',
            program=['full'],
            only_on_changed_files=True,
            continue_after_build_error=True,
        )
        + api.checkout.ci_test_data()
        + api.step_data('get build id', stdout=api.raw_io.output_text('0\n'),)
    )

    yield (
        api.test('step')
        + properties(
            step=['step1', 'step2'],
            use_time_for_rng_seed=True,
            override_gn_arg=('foo=1', 'bar=2'),
        )
        + api.checkout.try_test_data(
            start_time=datetime.datetime.utcfromtimestamp(1600000000),
            execution_timeout=120,
        )
        + api.time.seed(1600000000)
        + api.time.step(20.0)
    )

    yield (
        api.test('long')
        + properties(step=['step1', 'step2'])
        + api.checkout.try_test_data(
            start_time=datetime.datetime.utcfromtimestamp(1600000000),
            execution_timeout=3 * 60 * 60,
        )
        + api.time.seed(1600000000)
        + api.time.step(20.0)
    )

    yield (
        api.test('medium')
        + properties(step=['step1', 'step2'])
        + api.checkout.try_test_data(
            start_time=datetime.datetime.utcfromtimestamp(1600000000),
            execution_timeout=30 * 60,
        )
        + api.time.seed(1600000000)
        + api.time.step(20.0)
    )

    yield (
        api.test('comment-on-failure')
        + properties(
            step=['step1', 'step2'],
            comment_behavior=CommentBehavior.COMMENT_ON_FAILURE,
        )
        + api.checkout.try_test_data(
            start_time=datetime.datetime.utcfromtimestamp(1600000000),
            execution_timeout=120,
        )
        + api.time.seed(1600000000)
        + api.time.step(20.0)
    )

    yield (
        api.test('comment-always')
        + properties(
            step=['step1', 'step2'],
            comment_behavior=CommentBehavior.COMMENT_ALWAYS,
        )
        + api.checkout.try_test_data(
            start_time=datetime.datetime.utcfromtimestamp(1600000000),
            execution_timeout=120,
        )
        + api.time.seed(1600000000)
        + api.time.step(20.0)
    )

    yield (
        api.test('comment-always-no-cl')
        + properties(
            step=['step1', 'step2'],
            comment_behavior=CommentBehavior.COMMENT_ALWAYS,
        )
        + api.checkout.ci_test_data()
        + api.time.seed(1600000000)
        + api.time.step(20.0)
    )

    yield (
        api.test('comment-always-disallowed-host')
        + properties(
            step=['step1', 'step2'],
            comment_behavior=CommentBehavior.COMMENT_ALWAYS,
            comment_allowed_gerrit_hosts=['secret-host.googlesource.come'],
        )
        + api.checkout.try_test_data(
            start_time=datetime.datetime.utcfromtimestamp(1600000000),
            execution_timeout=120,
        )
        + api.time.seed(1600000000)
        + api.time.step(20.0)
    )
