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

import logging

from autotest_lib.client.bin import test
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib import utils


class detachablebase_TriggerHammerd(test.test):
    """Hammerd smoke test.

    Hammerd upstart job should be invoked on boot. The job should exit normally.

    Also, checks that hammerd enables USB autosuspend on the hammer device.
    """
    version = 1

    # The upstart job's name.
    PROCESS_NAME = 'hammerd'

    # Path of the system log.
    MESSAGE_PATH = '/var/log/messages'

    # Message to find the start line of each boot. The boot timing is usually
    # [    0.000000], but in case the boot process has delay, we accept any
    # timing within 1 second.
    BOOT_START_LINE_MSG = 'kernel: \[    0\.[0-9]\{6\}\] Linux version'

    # Message that is printed when hammerd is triggered on boot.
    # It is defined at `src/platform2/hammerd/init/hammerd-at-boot.sh`.
    TRIGGER_ON_BOOT_MSG = 'Force trigger hammerd at boot.'

    # Message that is printed when the hammerd job failed to terminated
    # normally.
    PROCESS_FAILED_MSG = '%s main process ([0-9]\+) terminated' % PROCESS_NAME

    # Hammerd writes path to USB device in that file.
    WRITE_SYSFS_PATH = '/run/metrics/external/hammer/hammer_sysfs_path'

    # Autosuspend control sysfs PATH (rooted at USB device sysfs path)
    SYSFS_POWER_CONTROL_PATH = 'power/control'

    def run_once(self):
        # Get the start line of message belonging to this current boot.
        start_line = utils.run(
                'grep -ni "%s" "%s" | tail -n 1 | cut -d ":" -f 1' %
                (self.BOOT_START_LINE_MSG, self.MESSAGE_PATH),
                ignore_status=True).stdout.strip()
        logging.info('Start line: %s', start_line)
        if not start_line:
            raise error.TestFail('Start line of boot is not found.')

        def _grep_messages(pattern):
            return utils.run('tail -n +%s %s | grep "%s"' %
                             (start_line, self.MESSAGE_PATH, pattern),
                             ignore_status=True).stdout

        # Check hammerd is triggered on boot.
        if not _grep_messages(self.TRIGGER_ON_BOOT_MSG):
            raise error.TestFail('hammerd is not triggered on boot.')
        # Check hammerd is terminated normally.
        if _grep_messages(self.PROCESS_FAILED_MSG):
            hammerd_log = _grep_messages(self.PROCESS_NAME)
            logging.error('Hammerd log: %s', hammerd_log)
            raise error.TestFail('hammerd terminated with non-zero value')

        # Check that hammerd wrote to WRITE_SYSFS_PATH
        sysfspath = utils.read_one_line(self.WRITE_SYSFS_PATH)

        if not sysfspath:
            raise error.TestFail('%s is empty' % (self.WRITE_SYSFS_PATH))

        # Check that autosuspend is enabled
        power = utils.read_one_line(sysfspath + '/' +
                                    self.SYSFS_POWER_CONTROL_PATH)
        if power != 'auto':
            raise error.TestFail('Autosuspend not enabled on hammer port')
