1# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging, os, time
6from autotest_lib.client.bin import test, utils
7from autotest_lib.client.common_lib import error
8from autotest_lib.client.cros import constants, cros_ui
9
10class desktopui_Respawn(test.test):
11    """Validate that the UI will cease respawning after a certain number of
12       attempts in a time window. By design, this test does _not_ attempt to
13       ensure that these values remain the same over time. The values are
14       somewhat arbitrary anyhow, so enforcing them is simply an
15       over-constraint.
16    """
17    version = 1
18
19    UNREASONABLY_HIGH_RESPAWN_COUNT = 90
20
21    def initialize(self):
22        """Clear out respawn timestamp files."""
23        cros_ui.clear_respawn_state()
24
25
26    def _nuke_ui_with_prejudice_and_wait(self, timeout):
27        """Nuke the UI with prejudice, then wait for it to come up.
28
29        @param timeout: time in seconds to wait for browser to come back."""
30        try:
31            utils.nuke_process_by_name(constants.SESSION_MANAGER,
32                                       with_prejudice=True)
33        except error.AutoservPidAlreadyDeadError:
34            pass
35        utils.poll_for_condition(
36            lambda: utils.get_oldest_pid_by_name(constants.SESSION_MANAGER),
37            desc='ui to come back up.',
38            timeout=timeout)
39
40
41    def run_once(self):
42        # Ensure the UI is running.
43        logging.debug('Restarting UI to ensure that it\'s running.')
44        cros_ui.stop(allow_fail=True)
45        cros_ui.start(wait_for_login_prompt=False)
46
47        # Nuke the UI continuously until it stops respawning.
48        respawned_at_least_once = False
49        attempt = 0
50        timeout_seconds = 10
51        start_time = time.time()
52        try:
53            for attempt in range(self.UNREASONABLY_HIGH_RESPAWN_COUNT):
54                self._nuke_ui_with_prejudice_and_wait(timeout_seconds)
55                respawned_at_least_once = True
56        except utils.TimeoutError as te:
57            start_time += timeout_seconds
58            pass
59        logging.info("Respawned UI %d times in %d seconds",
60                     attempt, time.time() - start_time)
61
62        if cros_ui.is_up():
63            raise error.TestFail(
64                'Respawning should have stopped before %d attempts' %
65                self.UNREASONABLY_HIGH_RESPAWN_COUNT)
66        if not respawned_at_least_once:
67            raise error.TestFail('Should have respawned at least once')
68
69
70    def cleanup(self):
71        """Ensure the UI is up, and that state from testing is cleared out."""
72        cros_ui.clear_respawn_state()
73        # If the UI is already up, we want to tolerate that.
74        cros_ui.start(allow_fail=True)
75