# Copyright (c) 2013 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, os, time
from autotest_lib.client.bin import test, utils
from autotest_lib.client.common_lib import error
from autotest_lib.client.cros import constants, cros_ui

class desktopui_Respawn(test.test):
    """Validate that the UI will cease respawning after a certain number of
       attempts in a time window. By design, this test does _not_ attempt to
       ensure that these values remain the same over time. The values are
       somewhat arbitrary anyhow, so enforcing them is simply an
       over-constraint.
    """
    version = 1

    UNREASONABLY_HIGH_RESPAWN_COUNT = 90

    def initialize(self):
        """Clear out respawn timestamp files."""
        cros_ui.clear_respawn_state()


    def _nuke_ui_with_prejudice_and_wait(self, timeout):
        """Nuke the UI with prejudice, then wait for it to come up.

        @param timeout: time in seconds to wait for browser to come back."""
        try:
            utils.nuke_process_by_name(constants.SESSION_MANAGER,
                                       with_prejudice=True)
        except error.AutoservPidAlreadyDeadError:
            pass
        utils.poll_for_condition(
            lambda: utils.get_oldest_pid_by_name(constants.SESSION_MANAGER),
            desc='ui to come back up.',
            timeout=timeout)


    def run_once(self):
        # Ensure the UI is running.
        logging.debug('Restarting UI to ensure that it\'s running.')
        cros_ui.stop(allow_fail=True)
        cros_ui.start(wait_for_login_prompt=False)

        # Nuke the UI continuously until it stops respawning.
        respawned_at_least_once = False
        attempt = 0
        timeout_seconds = 10
        start_time = time.time()
        try:
            for attempt in range(self.UNREASONABLY_HIGH_RESPAWN_COUNT):
                self._nuke_ui_with_prejudice_and_wait(timeout_seconds)
                respawned_at_least_once = True
        except utils.TimeoutError as te:
            start_time += timeout_seconds
            pass
        logging.info("Respawned UI %d times in %d seconds",
                     attempt, time.time() - start_time)

        if cros_ui.is_up():
            raise error.TestFail(
                'Respawning should have stopped before %d attempts' %
                self.UNREASONABLY_HIGH_RESPAWN_COUNT)
        if not respawned_at_least_once:
            raise error.TestFail('Should have respawned at least once')


    def cleanup(self):
        """Ensure the UI is up, and that state from testing is cleared out."""
        cros_ui.clear_respawn_state()
        # If the UI is already up, we want to tolerate that.
        cros_ui.start(allow_fail=True)