blob: 3e9c46b8d2a93845014bfdaff8e0bb3f4134c0ad [file] [log] [blame]
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001#!/usr/bin/python -u
Hung-Te Linf2f78f72012-02-08 19:27:11 +08002# -*- coding: utf-8 -*-
3#
Jon Salz37eccbd2012-05-25 16:06:52 +08004# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Hung-Te Linf2f78f72012-02-08 19:27:11 +08005# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08008"""The main factory flow that runs the factory test and finalizes a device."""
Hung-Te Linf2f78f72012-02-08 19:27:11 +08009
Joel Kitchingb85ed7f2014-10-08 18:24:39 +080010from __future__ import print_function
11
Jon Salze12c2b32013-06-25 16:24:34 +080012import glob
Jon Salz0405ab52012-03-16 15:26:52 +080013import logging
14import os
Jon Salze12c2b32013-06-25 16:24:34 +080015import shutil
Jon Salz77c151e2012-08-28 07:20:37 +080016import signal
Jon Salz0405ab52012-03-16 15:26:52 +080017import sys
Jon Salzeff94182013-06-19 15:06:28 +080018import syslog
Jon Salz0405ab52012-03-16 15:26:52 +080019import threading
20import time
21import traceback
Jon Salz258a40c2012-04-19 12:34:01 +080022import uuid
Jon Salzb10cf512012-08-09 17:29:21 +080023from xmlrpclib import Binary
Hung-Te Linf2f78f72012-02-08 19:27:11 +080024from collections import deque
25from optparse import OptionParser
Hung-Te Linf2f78f72012-02-08 19:27:11 +080026
Jon Salz0697cbf2012-07-04 15:14:04 +080027import factory_common # pylint: disable=W0611
Hung-Te Lin91492a12014-11-25 18:56:30 +080028from cros.factory.test import event_log
jcliangcd688182012-08-20 21:01:26 +080029from cros.factory import system
Hung-Te Lin91492a12014-11-25 18:56:30 +080030from cros.factory.test.event_log import EventLog, FloatDigit
Hung-Te Lincc41d2a2014-10-29 13:35:20 +080031from cros.factory.goofy import connection_manager
Vic Yangd80ea752014-09-24 16:07:14 +080032from cros.factory.goofy import test_environment
33from cros.factory.goofy import time_sanitizer
34from cros.factory.goofy import updater
35from cros.factory.goofy.goofy_base import GoofyBase
36from cros.factory.goofy.goofy_rpc import GoofyRPC
37from cros.factory.goofy.invocation import TestArgEnv
38from cros.factory.goofy.invocation import TestInvocation
39from cros.factory.goofy.link_manager import PresenterLinkManager
Vic Yange2c76a82014-10-30 12:48:19 -070040from cros.factory.goofy import prespawner
Vic Yangd80ea752014-09-24 16:07:14 +080041from cros.factory.goofy.system_log_manager import SystemLogManager
Wei-Ning Huang38b75f02015-02-25 18:25:14 +080042from cros.factory.goofy.terminal_manager import TerminalManager
Vic Yangd80ea752014-09-24 16:07:14 +080043from cros.factory.goofy.web_socket_manager import WebSocketManager
Cheng-Yi Chiangd8186952013-04-04 23:41:14 +080044from cros.factory.system.board import Board, BoardException
jcliangcd688182012-08-20 21:01:26 +080045from cros.factory.system.charge_manager import ChargeManager
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +080046from cros.factory.system.core_dump_manager import CoreDumpManager
Jon Salzce6a7f82013-06-10 18:22:54 +080047from cros.factory.system.cpufreq_manager import CpufreqManager
Jon Salzb92c5112012-09-21 15:40:11 +080048from cros.factory.system import disk_space
jcliangcd688182012-08-20 21:01:26 +080049from cros.factory.test import factory
Jon Salz670ce062014-05-16 15:53:50 +080050from cros.factory.test import phase
jcliangcd688182012-08-20 21:01:26 +080051from cros.factory.test import state
Jon Salz51528e12012-07-02 18:54:45 +080052from cros.factory.test import shopfloor
Jon Salz83591782012-06-26 11:09:58 +080053from cros.factory.test import utils
Jon Salz128b0932013-07-03 16:55:26 +080054from cros.factory.test.test_lists import test_lists
Ricky Liang6fe218c2013-12-27 15:17:17 +080055from cros.factory.test.e2e_test.common import (
56 AutomationMode, AutomationModePrompt, ParseAutomationMode)
Jon Salz83591782012-06-26 11:09:58 +080057from cros.factory.test.event import Event
58from cros.factory.test.event import EventClient
59from cros.factory.test.event import EventServer
Hung-Te Lin91492a12014-11-25 18:56:30 +080060from cros.factory.test.event_log_watcher import EventLogWatcher
jcliangcd688182012-08-20 21:01:26 +080061from cros.factory.test.factory import TestState
Jon Salzd7550792013-07-12 05:49:27 +080062from cros.factory.test.utils import Enum
Dean Liao592e4d52013-01-10 20:06:39 +080063from cros.factory.tools.key_filter import KeyFilter
Jon Salz2af235d2013-06-24 14:47:21 +080064from cros.factory.utils import file_utils
Joel Kitchingb85ed7f2014-10-08 18:24:39 +080065from cros.factory.utils import net_utils
Jon Salz78c32392012-07-25 14:18:29 +080066from cros.factory.utils.process_utils import Spawn
Hung-Te Linf2f78f72012-02-08 19:27:11 +080067
68
Hung-Te Linf2f78f72012-02-08 19:27:11 +080069HWID_CFG_PATH = '/usr/local/share/chromeos-hwid/cfg'
Ricky Liang45c73e72015-01-15 15:00:30 +080070CACHES_DIR = os.path.join(factory.get_state_root(), 'caches')
Hung-Te Linf2f78f72012-02-08 19:27:11 +080071
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +080072CLEANUP_LOGS_PAUSED = '/var/lib/cleanup_logs_paused'
73
Jon Salz5c344f62012-07-13 14:31:16 +080074# Value for tests_after_shutdown that forces auto-run (e.g., after
75# a factory update, when the available set of tests might change).
76FORCE_AUTO_RUN = 'force_auto_run'
77
Justin Chuang83813982013-05-13 01:26:32 +080078# Sync disks when battery level is higher than this value.
79# Otherwise, power loss during disk sync operation may incur even worse outcome.
80MIN_BATTERY_LEVEL_FOR_DISK_SYNC = 1.0
81
Ricky Liang45c73e72015-01-15 15:00:30 +080082MAX_CRASH_FILE_SIZE = 64 * 1024
Jon Salze12c2b32013-06-25 16:24:34 +080083
Jon Salzd7550792013-07-12 05:49:27 +080084Status = Enum(['UNINITIALIZED', 'INITIALIZING', 'RUNNING',
85 'TERMINATING', 'TERMINATED'])
86
Ricky Liang45c73e72015-01-15 15:00:30 +080087
Hung-Te Linf2f78f72012-02-08 19:27:11 +080088def get_hwid_cfg():
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +080089 """Returns the HWID config tag, or an empty string if none can be found."""
Jon Salz0697cbf2012-07-04 15:14:04 +080090 if 'CROS_HWID' in os.environ:
91 return os.environ['CROS_HWID']
92 if os.path.exists(HWID_CFG_PATH):
Ricky Liang45c73e72015-01-15 15:00:30 +080093 with open(HWID_CFG_PATH, 'r') as hwid_cfg_handle:
Jon Salz0697cbf2012-07-04 15:14:04 +080094 return hwid_cfg_handle.read().strip()
95 return ''
Hung-Te Linf2f78f72012-02-08 19:27:11 +080096
97
Jon Salz73e0fd02012-04-04 11:46:38 +080098_inited_logging = False
Hung-Te Linf2f78f72012-02-08 19:27:11 +080099
Ricky Liang45c73e72015-01-15 15:00:30 +0800100
Peter Ammon1e1ec572014-06-26 17:56:32 -0700101class Goofy(GoofyBase):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800102 """The main factory flow.
Jon Salz0697cbf2012-07-04 15:14:04 +0800103
104 Note that all methods in this class must be invoked from the main
105 (event) thread. Other threads, such as callbacks and TestInvocation
106 methods, should instead post events on the run queue.
107
108 TODO: Unit tests. (chrome-os-partner:7409)
109
110 Properties:
111 uuid: A unique UUID for this invocation of Goofy.
112 state_instance: An instance of FactoryState.
113 state_server: The FactoryState XML/RPC server.
114 state_server_thread: A thread running state_server.
115 event_server: The EventServer socket server.
116 event_server_thread: A thread running event_server.
117 event_client: A client to the event server.
118 connection_manager: The connection_manager object.
Cheng-Yi Chiang835f2682013-05-06 22:15:48 +0800119 system_log_manager: The SystemLogManager object.
120 core_dump_manager: The CoreDumpManager object.
Jon Salz0697cbf2012-07-04 15:14:04 +0800121 ui_process: The factory ui process object.
Jon Salz0697cbf2012-07-04 15:14:04 +0800122 invocations: A map from FactoryTest objects to the corresponding
123 TestInvocations objects representing active tests.
124 tests_to_run: A deque of tests that should be run when the current
125 test(s) complete.
126 options: Command-line options.
127 args: Command-line args.
128 test_list: The test list.
Jon Salz128b0932013-07-03 16:55:26 +0800129 test_lists: All new-style test lists.
Ricky Liang4bff3e32014-02-20 18:46:11 +0800130 run_id: The identifier for latest test run.
131 scheduled_run_tests: The list of tests scheduled for latest test run.
Jon Salz0697cbf2012-07-04 15:14:04 +0800132 event_handlers: Map of Event.Type to the method used to handle that
133 event. If the method has an 'event' argument, the event is passed
134 to the handler.
Jon Salz3c493bb2013-02-07 17:24:58 +0800135 last_log_disk_space_message: The last message we logged about disk space
136 (to avoid duplication).
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +0800137 last_kick_sync_time: The last time to kick system_log_manager to sync
138 because of core dump files (to avoid kicking too soon then abort the
139 sync.)
Jon Salz416f9cc2013-05-10 18:32:50 +0800140 hooks: A Hooks object containing hooks for various Goofy actions.
Jon Salzd7550792013-07-12 05:49:27 +0800141 status: The current Goofy status (a member of the Status enum).
Peter Ammon948b7172014-07-15 12:43:06 -0700142 link_manager: Instance of PresenterLinkManager for communicating
143 with GoofyPresenter
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800144 """
Ricky Liang45c73e72015-01-15 15:00:30 +0800145
Jon Salz0697cbf2012-07-04 15:14:04 +0800146 def __init__(self):
Peter Ammon1e1ec572014-06-26 17:56:32 -0700147 super(Goofy, self).__init__()
Jon Salz0697cbf2012-07-04 15:14:04 +0800148 self.uuid = str(uuid.uuid4())
149 self.state_instance = None
150 self.state_server = None
151 self.state_server_thread = None
Jon Salz16d10542012-07-23 12:18:45 +0800152 self.goofy_rpc = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800153 self.event_server = None
154 self.event_server_thread = None
155 self.event_client = None
156 self.connection_manager = None
Vic Yang4953fc12012-07-26 16:19:53 +0800157 self.charge_manager = None
Dean Liao88b93192014-10-23 19:37:41 +0800158 self._can_charge = True
Jon Salz8fa8e832012-07-13 19:04:09 +0800159 self.time_sanitizer = None
160 self.time_synced = False
Jon Salz0697cbf2012-07-04 15:14:04 +0800161 self.log_watcher = None
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800162 self.system_log_manager = None
Cheng-Yi Chiang835f2682013-05-06 22:15:48 +0800163 self.core_dump_manager = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800164 self.event_log = None
Vic Yange2c76a82014-10-30 12:48:19 -0700165 self.autotest_prespawner = None
166 self.pytest_prespawner = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800167 self.ui_process = None
Vic Yanga3cecf82014-12-26 00:44:21 -0800168 self._ui_initialized = False
Jon Salzc79a9982012-08-30 04:42:01 +0800169 self.dummy_shopfloor = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800170 self.invocations = {}
171 self.tests_to_run = deque()
172 self.visible_test = None
173 self.chrome = None
Jon Salz416f9cc2013-05-10 18:32:50 +0800174 self.hooks = None
Vic Yangd8990da2013-06-27 16:57:43 +0800175 self.cpu_usage_watcher = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800176
177 self.options = None
178 self.args = None
179 self.test_list = None
Jon Salz128b0932013-07-03 16:55:26 +0800180 self.test_lists = None
Ricky Liang4bff3e32014-02-20 18:46:11 +0800181 self.run_id = None
182 self.scheduled_run_tests = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800183 self.env = None
Jon Salzb22d1172012-08-06 10:38:57 +0800184 self.last_idle = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800185 self.last_shutdown_time = None
cychiang21886742012-07-05 15:16:32 +0800186 self.last_update_check = None
Jon Salz8fa8e832012-07-13 19:04:09 +0800187 self.last_sync_time = None
Jon Salzb92c5112012-09-21 15:40:11 +0800188 self.last_log_disk_space_time = None
Jon Salz3c493bb2013-02-07 17:24:58 +0800189 self.last_log_disk_space_message = None
Justin Chuang83813982013-05-13 01:26:32 +0800190 self.last_check_battery_time = None
191 self.last_check_battery_message = None
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +0800192 self.last_kick_sync_time = None
Vic Yang311ddb82012-09-26 12:08:28 +0800193 self.exclusive_items = set()
Jon Salz0f996602012-10-03 15:26:48 +0800194 self.event_log = None
Dean Liao592e4d52013-01-10 20:06:39 +0800195 self.key_filter = None
Jon Salzce6a7f82013-06-10 18:22:54 +0800196 self.cpufreq_manager = None
Jon Salzd7550792013-07-12 05:49:27 +0800197 self.status = Status.UNINITIALIZED
Ricky Liang36512a32014-07-25 11:47:04 +0800198 self.ready_for_ui_connection = False
Peter Ammon1e1ec572014-06-26 17:56:32 -0700199 self.link_manager = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800200
Jon Salz85a39882012-07-05 16:45:04 +0800201 def test_or_root(event, parent_or_group=True):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800202 """Returns the test affected by a particular event.
Jon Salz85a39882012-07-05 16:45:04 +0800203
204 Args:
205 event: The event containing an optional 'path' attribute.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800206 parent_or_group: If True, returns the top-level parent for a test (the
Jon Salz85a39882012-07-05 16:45:04 +0800207 root node of the tests that need to be run together if the given test
208 path is to be run).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800209 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800210 try:
211 path = event.path
212 except AttributeError:
213 path = None
214
215 if path:
Jon Salz85a39882012-07-05 16:45:04 +0800216 test = self.test_list.lookup_path(path)
217 if parent_or_group:
218 test = test.get_top_level_parent_or_group()
219 return test
Jon Salz0697cbf2012-07-04 15:14:04 +0800220 else:
221 return self.test_list
222
223 self.event_handlers = {
Ricky Liang45c73e72015-01-15 15:00:30 +0800224 Event.Type.SWITCH_TEST: self.handle_switch_test,
225 Event.Type.SHOW_NEXT_ACTIVE_TEST:
226 lambda event: self.show_next_active_test(),
227 Event.Type.RESTART_TESTS:
228 lambda event: self.restart_tests(root=test_or_root(event)),
229 Event.Type.AUTO_RUN:
230 lambda event: self.auto_run(root=test_or_root(event)),
231 Event.Type.RE_RUN_FAILED:
232 lambda event: self.re_run_failed(root=test_or_root(event)),
233 Event.Type.RUN_TESTS_WITH_STATUS:
234 lambda event: self.run_tests_with_status(
235 event.status,
236 root=test_or_root(event)),
237 Event.Type.REVIEW:
238 lambda event: self.show_review_information(),
239 Event.Type.UPDATE_SYSTEM_INFO:
240 lambda event: self.update_system_info(),
241 Event.Type.STOP:
242 lambda event: self.stop(root=test_or_root(event, False),
243 fail=getattr(event, 'fail', False),
244 reason=getattr(event, 'reason', None)),
245 Event.Type.SET_VISIBLE_TEST:
246 lambda event: self.set_visible_test(
247 self.test_list.lookup_path(event.path)),
248 Event.Type.CLEAR_STATE:
249 lambda event: self.clear_state(
250 self.test_list.lookup_path(event.path)),
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800251 Event.Type.KEY_FILTER_MODE: self.handle_key_filter_mode,
Jon Salz0697cbf2012-07-04 15:14:04 +0800252 }
253
Jon Salz0697cbf2012-07-04 15:14:04 +0800254 self.web_socket_manager = None
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800255 self.terminal_manager = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800256
257 def destroy(self):
Ricky Liang74237a02014-09-18 15:11:23 +0800258 """Performs any shutdown tasks. Overrides base class method."""
Jon Salzd7550792013-07-12 05:49:27 +0800259 self.status = Status.TERMINATING
Jon Salz0697cbf2012-07-04 15:14:04 +0800260 if self.chrome:
261 self.chrome.kill()
262 self.chrome = None
Jon Salzc79a9982012-08-30 04:42:01 +0800263 if self.dummy_shopfloor:
264 self.dummy_shopfloor.kill()
265 self.dummy_shopfloor = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800266 if self.ui_process:
267 utils.kill_process_tree(self.ui_process, 'ui')
268 self.ui_process = None
269 if self.web_socket_manager:
270 logging.info('Stopping web sockets')
271 self.web_socket_manager.close()
272 self.web_socket_manager = None
273 if self.state_server_thread:
274 logging.info('Stopping state server')
275 self.state_server.shutdown()
276 self.state_server_thread.join()
277 self.state_server.server_close()
278 self.state_server_thread = None
279 if self.state_instance:
280 self.state_instance.close()
281 if self.event_server_thread:
282 logging.info('Stopping event server')
283 self.event_server.shutdown() # pylint: disable=E1101
284 self.event_server_thread.join()
285 self.event_server.server_close()
286 self.event_server_thread = None
287 if self.log_watcher:
288 if self.log_watcher.IsThreadStarted():
289 self.log_watcher.StopWatchThread()
290 self.log_watcher = None
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800291 if self.system_log_manager:
292 if self.system_log_manager.IsThreadRunning():
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +0800293 self.system_log_manager.Stop()
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800294 self.system_log_manager = None
Vic Yange2c76a82014-10-30 12:48:19 -0700295 if self.autotest_prespawner:
296 logging.info('Stopping autotest prespawner')
297 self.autotest_prespawner.stop()
298 self.autotest_prespawner = None
299 if self.pytest_prespawner:
300 logging.info('Stopping pytest prespawner')
301 self.pytest_prespawner.stop()
302 self.pytest_prespawner = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800303 if self.event_client:
304 logging.info('Closing event client')
305 self.event_client.close()
306 self.event_client = None
Jon Salzddf0d052013-06-18 12:52:44 +0800307 if self.cpufreq_manager:
308 self.cpufreq_manager.Stop()
Jon Salz0697cbf2012-07-04 15:14:04 +0800309 if self.event_log:
310 self.event_log.Close()
311 self.event_log = None
Dean Liao592e4d52013-01-10 20:06:39 +0800312 if self.key_filter:
313 self.key_filter.Stop()
Vic Yangd8990da2013-06-27 16:57:43 +0800314 if self.cpu_usage_watcher:
315 self.cpu_usage_watcher.terminate()
Peter Ammon1e1ec572014-06-26 17:56:32 -0700316 if self.link_manager:
317 self.link_manager.Stop()
318 self.link_manager = None
Dean Liao592e4d52013-01-10 20:06:39 +0800319
Peter Ammon1e1ec572014-06-26 17:56:32 -0700320 super(Goofy, self).destroy()
Jon Salz0697cbf2012-07-04 15:14:04 +0800321 logging.info('Done destroying Goofy')
Jon Salzd7550792013-07-12 05:49:27 +0800322 self.status = Status.TERMINATED
Jon Salz0697cbf2012-07-04 15:14:04 +0800323
324 def start_state_server(self):
Jon Salz2af235d2013-06-24 14:47:21 +0800325 # Before starting state server, remount stateful partitions with
326 # no commit flag. The default commit time (commit=600) makes corruption
327 # too likely.
Hung-Te Lind59dbfa2014-08-27 12:27:53 +0800328 utils.ResetCommitTime()
Jon Salz2af235d2013-06-24 14:47:21 +0800329
Jon Salz0697cbf2012-07-04 15:14:04 +0800330 self.state_instance, self.state_server = (
Ricky Liang45c73e72015-01-15 15:00:30 +0800331 state.create_server(bind_address='0.0.0.0'))
Jon Salz16d10542012-07-23 12:18:45 +0800332 self.goofy_rpc = GoofyRPC(self)
333 self.goofy_rpc.RegisterMethods(self.state_instance)
Jon Salz0697cbf2012-07-04 15:14:04 +0800334 logging.info('Starting state server')
335 self.state_server_thread = threading.Thread(
Ricky Liang45c73e72015-01-15 15:00:30 +0800336 target=self.state_server.serve_forever,
337 name='StateServer')
Jon Salz0697cbf2012-07-04 15:14:04 +0800338 self.state_server_thread.start()
339
340 def start_event_server(self):
341 self.event_server = EventServer()
342 logging.info('Starting factory event server')
343 self.event_server_thread = threading.Thread(
Ricky Liang45c73e72015-01-15 15:00:30 +0800344 target=self.event_server.serve_forever,
345 name='EventServer') # pylint: disable=E1101
Jon Salz0697cbf2012-07-04 15:14:04 +0800346 self.event_server_thread.start()
347
348 self.event_client = EventClient(
Ricky Liang45c73e72015-01-15 15:00:30 +0800349 callback=self.handle_event, event_loop=self.run_queue)
Jon Salz0697cbf2012-07-04 15:14:04 +0800350
351 self.web_socket_manager = WebSocketManager(self.uuid)
Ricky Liang45c73e72015-01-15 15:00:30 +0800352 self.state_server.add_handler('/event',
353 self.web_socket_manager.handle_web_socket)
Jon Salz0697cbf2012-07-04 15:14:04 +0800354
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800355 def start_terminal_server(self):
356 self.terminal_manager = TerminalManager()
357 self.state_server.add_handler('/pty',
358 self.terminal_manager.handle_web_socket)
359
Jon Salz0697cbf2012-07-04 15:14:04 +0800360 def start_ui(self):
361 ui_proc_args = [
Ricky Liang45c73e72015-01-15 15:00:30 +0800362 os.path.join(factory.FACTORY_PACKAGE_PATH, 'test', 'ui.py'),
363 self.options.test_list
364 ]
Jon Salz0697cbf2012-07-04 15:14:04 +0800365 if self.options.verbose:
366 ui_proc_args.append('-v')
367 logging.info('Starting ui %s', ui_proc_args)
Jon Salz78c32392012-07-25 14:18:29 +0800368 self.ui_process = Spawn(ui_proc_args)
Jon Salz0697cbf2012-07-04 15:14:04 +0800369 logging.info('Waiting for UI to come up...')
370 self.event_client.wait(
Ricky Liang45c73e72015-01-15 15:00:30 +0800371 lambda event: event.type == Event.Type.UI_READY)
Jon Salz0697cbf2012-07-04 15:14:04 +0800372 logging.info('UI has started')
373
374 def set_visible_test(self, test):
375 if self.visible_test == test:
376 return
Jon Salz2f2d42c2012-07-30 12:30:34 +0800377 if test and not test.has_ui:
378 return
Jon Salz0697cbf2012-07-04 15:14:04 +0800379
380 if test:
381 test.update_state(visible=True)
382 if self.visible_test:
383 self.visible_test.update_state(visible=False)
384 self.visible_test = test
385
Ricky Liang48e47f92014-02-26 19:31:51 +0800386 def log_startup_messages(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800387 """Logs the tail of var/log/messages and mosys and EC console logs."""
Jon Salzd4306c82012-11-30 15:16:36 +0800388 # TODO(jsalz): This is mostly a copy-and-paste of code in init_states,
389 # for factory-3004.B only. Consolidate and merge back to ToT.
390 if utils.in_chroot():
391 return
392
393 try:
Ricky Liang45c73e72015-01-15 15:00:30 +0800394 var_log_messages = utils.var_log_messages_before_reboot()
Jon Salzd4306c82012-11-30 15:16:36 +0800395 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +0800396 'Tail of /var/log/messages before last reboot:\n'
397 '%s', ('\n'.join(
398 ' ' + x for x in var_log_messages)))
Jon Salzd4306c82012-11-30 15:16:36 +0800399 except: # pylint: disable=W0702
400 logging.exception('Unable to grok /var/log/messages')
401
402 try:
Ricky Liang117484a2014-04-14 11:14:41 +0800403 mosys_log = Spawn(
Jon Salzd4306c82012-11-30 15:16:36 +0800404 ['mosys', 'eventlog', 'list'],
405 read_stdout=True, log_stderr_on_error=True).stdout_data
406 logging.info('System eventlog from mosys:\n%s\n', mosys_log)
407 except: # pylint: disable=W0702
408 logging.exception('Unable to read mosys eventlog')
409
Dean Liao88b93192014-10-23 19:37:41 +0800410 self.log_ec_console()
411 self.log_ec_panic_info()
412
413 @staticmethod
414 def log_ec_console():
415 """Logs EC console log into logging.info.
416
417 It logs an error message in logging.exception if an exception is raised
418 when getting EC console log.
419 For unsupported device, it logs unsupport message in logging.info
420
421 Returns:
422 EC console log string.
423 """
Jon Salzd4306c82012-11-30 15:16:36 +0800424 try:
Vic Yang8341dde2013-01-29 16:48:52 +0800425 board = system.GetBoard()
426 ec_console_log = board.GetECConsoleLog()
Jon Salzd4306c82012-11-30 15:16:36 +0800427 logging.info('EC console log after reboot:\n%s\n', ec_console_log)
Dean Liao88b93192014-10-23 19:37:41 +0800428 return ec_console_log
429 except NotImplementedError:
430 logging.info('EC console log not supported')
Jon Salzd4306c82012-11-30 15:16:36 +0800431 except: # pylint: disable=W0702
432 logging.exception('Error retrieving EC console log')
433
Dean Liao88b93192014-10-23 19:37:41 +0800434 @staticmethod
435 def log_ec_panic_info():
436 """Logs EC panic info into logging.info.
437
438 It logs an error message in logging.exception if an exception is raised
439 when getting EC panic info.
440 For unsupported device, it logs unsupport message in logging.info
441
442 Returns:
443 EC panic info string.
444 """
Vic Yang079f9872013-07-01 11:32:00 +0800445 try:
446 board = system.GetBoard()
447 ec_panic_info = board.GetECPanicInfo()
448 logging.info('EC panic info after reboot:\n%s\n', ec_panic_info)
Dean Liao88b93192014-10-23 19:37:41 +0800449 return ec_panic_info
450 except NotImplementedError:
451 logging.info('EC panic info is not supported')
Vic Yang079f9872013-07-01 11:32:00 +0800452 except: # pylint: disable=W0702
453 logging.exception('Error retrieving EC panic info')
454
Ricky Liang48e47f92014-02-26 19:31:51 +0800455 def shutdown(self, operation):
456 """Starts shutdown procedure.
457
458 Args:
Vic (Chun-Ju) Yang05b0d952014-04-28 17:39:09 +0800459 operation: The shutdown operation (reboot, full_reboot, or halt).
Ricky Liang48e47f92014-02-26 19:31:51 +0800460 """
461 active_tests = []
462 for test in self.test_list.walk():
463 if not test.is_leaf():
464 continue
465
466 test_state = test.get_state()
467 if test_state.status == TestState.ACTIVE:
468 active_tests.append(test)
469
Ricky Liang48e47f92014-02-26 19:31:51 +0800470 if not (len(active_tests) == 1 and
471 isinstance(active_tests[0], factory.ShutdownStep)):
472 logging.error(
473 'Calling Goofy shutdown outside of the shutdown factory test')
474 return
475
476 logging.info('Start Goofy shutdown (%s)', operation)
477 # Save pending test list in the state server
478 self.state_instance.set_shared_data(
479 'tests_after_shutdown',
480 [t.path for t in self.tests_to_run])
481 # Save shutdown time
482 self.state_instance.set_shared_data('shutdown_time', time.time())
483
484 with self.env.lock:
485 self.event_log.Log('shutdown', operation=operation)
486 shutdown_result = self.env.shutdown(operation)
487 if shutdown_result:
488 # That's all, folks!
Peter Ammon1e1ec572014-06-26 17:56:32 -0700489 self.run_enqueue(None)
Ricky Liang48e47f92014-02-26 19:31:51 +0800490 else:
491 # Just pass (e.g., in the chroot).
492 self.state_instance.set_shared_data('tests_after_shutdown', None)
493 # Send event with no fields to indicate that there is no
494 # longer a pending shutdown.
495 self.event_client.post_event(Event(Event.Type.PENDING_SHUTDOWN))
496
497 def handle_shutdown_complete(self, test):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800498 """Handles the case where a shutdown was detected during a shutdown step.
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800499
Ricky Liang6fe218c2013-12-27 15:17:17 +0800500 Args:
501 test: The ShutdownStep.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800502 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800503 test_state = test.update_state(increment_shutdown_count=1)
504 logging.info('Detected shutdown (%d of %d)',
Ricky Liang48e47f92014-02-26 19:31:51 +0800505 test_state.shutdown_count, test.iterations)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800506
Ricky Liang48e47f92014-02-26 19:31:51 +0800507 # Insert current shutdown test at the front of the list of tests to run
508 # after shutdown. This is to continue on post-shutdown verification in the
509 # shutdown step.
510 tests_after_shutdown = self.state_instance.get_shared_data(
511 'tests_after_shutdown', optional=True)
512 if not tests_after_shutdown:
513 self.state_instance.set_shared_data('tests_after_shutdown', [test.path])
514 elif isinstance(tests_after_shutdown, list):
515 self.state_instance.set_shared_data(
516 'tests_after_shutdown', [test.path] + tests_after_shutdown)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800517
Ricky Liang48e47f92014-02-26 19:31:51 +0800518 # Set 'post_shutdown' to inform shutdown test that a shutdown just occurred.
Ricky Liangb7eb8772014-09-15 18:05:22 +0800519 self.state_instance.set_shared_data(
520 state.POST_SHUTDOWN_TAG % test.path,
521 self.state_instance.get_test_state(test.path).invocation)
Jon Salz258a40c2012-04-19 12:34:01 +0800522
Jon Salz0697cbf2012-07-04 15:14:04 +0800523 def init_states(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800524 """Initializes all states on startup."""
Jon Salz0697cbf2012-07-04 15:14:04 +0800525 for test in self.test_list.get_all_tests():
526 # Make sure the state server knows about all the tests,
527 # defaulting to an untested state.
528 test.update_state(update_parent=False, visible=False)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800529
Jon Salz0697cbf2012-07-04 15:14:04 +0800530 var_log_messages = None
Vic Yanga9c32212012-08-16 20:07:54 +0800531 mosys_log = None
Vic Yange4c275d2012-08-28 01:50:20 +0800532 ec_console_log = None
Vic Yang079f9872013-07-01 11:32:00 +0800533 ec_panic_info = None
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800534
Jon Salz0697cbf2012-07-04 15:14:04 +0800535 # Any 'active' tests should be marked as failed now.
536 for test in self.test_list.walk():
Jon Salza6711d72012-07-18 14:33:03 +0800537 if not test.is_leaf():
538 # Don't bother with parents; they will be updated when their
539 # children are updated.
540 continue
541
Jon Salz0697cbf2012-07-04 15:14:04 +0800542 test_state = test.get_state()
543 if test_state.status != TestState.ACTIVE:
544 continue
545 if isinstance(test, factory.ShutdownStep):
546 # Shutdown while the test was active - that's good.
Ricky Liang48e47f92014-02-26 19:31:51 +0800547 self.handle_shutdown_complete(test)
Jon Salz0697cbf2012-07-04 15:14:04 +0800548 else:
549 # Unexpected shutdown. Grab /var/log/messages for context.
550 if var_log_messages is None:
551 try:
552 var_log_messages = (
Ricky Liang45c73e72015-01-15 15:00:30 +0800553 utils.var_log_messages_before_reboot())
Jon Salz0697cbf2012-07-04 15:14:04 +0800554 # Write it to the log, to make it easier to
555 # correlate with /var/log/messages.
556 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +0800557 'Unexpected shutdown. '
558 'Tail of /var/log/messages before last reboot:\n'
559 '%s', ('\n'.join(
560 ' ' + x for x in var_log_messages)))
Jon Salz0697cbf2012-07-04 15:14:04 +0800561 except: # pylint: disable=W0702
562 logging.exception('Unable to grok /var/log/messages')
563 var_log_messages = []
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800564
Jon Salz008f4ea2012-08-28 05:39:45 +0800565 if mosys_log is None and not utils.in_chroot():
566 try:
Ricky Liang117484a2014-04-14 11:14:41 +0800567 mosys_log = Spawn(
Jon Salz008f4ea2012-08-28 05:39:45 +0800568 ['mosys', 'eventlog', 'list'],
569 read_stdout=True, log_stderr_on_error=True).stdout_data
570 # Write it to the log also.
571 logging.info('System eventlog from mosys:\n%s\n', mosys_log)
572 except: # pylint: disable=W0702
573 logging.exception('Unable to read mosys eventlog')
Vic Yanga9c32212012-08-16 20:07:54 +0800574
Vic Yange4c275d2012-08-28 01:50:20 +0800575 if ec_console_log is None:
Dean Liao88b93192014-10-23 19:37:41 +0800576 ec_console_log = self.log_ec_console()
Vic Yange4c275d2012-08-28 01:50:20 +0800577
Vic Yang079f9872013-07-01 11:32:00 +0800578 if ec_panic_info is None:
Dean Liao88b93192014-10-23 19:37:41 +0800579 ec_panic_info = self.log_ec_panic_info()
Vic Yang079f9872013-07-01 11:32:00 +0800580
Jon Salz0697cbf2012-07-04 15:14:04 +0800581 error_msg = 'Unexpected shutdown while test was running'
582 self.event_log.Log('end_test',
Ricky Liang45c73e72015-01-15 15:00:30 +0800583 path=test.path,
584 status=TestState.FAILED,
585 invocation=test.get_state().invocation,
586 error_msg=error_msg,
587 var_log_messages='\n'.join(var_log_messages),
588 mosys_log=mosys_log)
Jon Salz0697cbf2012-07-04 15:14:04 +0800589 test.update_state(
Ricky Liang45c73e72015-01-15 15:00:30 +0800590 status=TestState.FAILED,
591 error_msg=error_msg)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800592
Jon Salz50efe942012-07-26 11:54:10 +0800593 if not test.never_fails:
594 # For "never_fails" tests (such as "Start"), don't cancel
595 # pending tests, since reboot is expected.
596 factory.console.info('Unexpected shutdown while test %s '
597 'running; cancelling any pending tests',
598 test.path)
599 self.state_instance.set_shared_data('tests_after_shutdown', [])
Jon Salz69806bb2012-07-20 18:05:02 +0800600
Jon Salz008f4ea2012-08-28 05:39:45 +0800601 self.update_skipped_tests()
602
603 def update_skipped_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800604 """Updates skipped states based on run_if."""
Jon Salz885dcac2013-07-23 16:39:50 +0800605 env = TestArgEnv()
Ricky Liang45c73e72015-01-15 15:00:30 +0800606
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800607 def _evaluate_skip_from_run_if(test):
608 """Returns the run_if evaluation of the test.
609
610 Args:
611 test: A FactoryTest object.
612
613 Returns:
614 The run_if evaluation result. Returns False if the test has no
615 run_if argument.
616 """
617 value = None
618 if test.run_if_expr:
619 try:
620 value = test.run_if_expr(env)
621 except: # pylint: disable=W0702
622 logging.exception('Unable to evaluate run_if expression for %s',
623 test.path)
624 # But keep going; we have no choice. This will end up
625 # always activating the test.
626 elif test.run_if_table_name:
627 try:
628 aux = shopfloor.get_selected_aux_data(test.run_if_table_name)
629 value = aux.get(test.run_if_col)
630 except ValueError:
631 # Not available; assume it shouldn't be skipped
632 pass
633
634 if value is None:
635 skip = False
636 else:
637 skip = (not value) ^ t.run_if_not
638 return skip
639
640 # Gets all run_if evaluation, and stores results in skip_map.
641 skip_map = dict()
Jon Salz008f4ea2012-08-28 05:39:45 +0800642 for t in self.test_list.walk():
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800643 skip_map[t.path] = _evaluate_skip_from_run_if(t)
Jon Salz885dcac2013-07-23 16:39:50 +0800644
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800645 # Propagates the skip value from root of tree and updates skip_map.
646 def _update_skip_map_from_node(test, skip_from_parent):
647 """Updates skip_map from a given node.
Jon Salz885dcac2013-07-23 16:39:50 +0800648
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800649 Given a FactoryTest node and the skip value from parent, updates the
650 skip value of current node in the skip_map if skip value from parent is
651 True. If this node has children, recursively propagate this value to all
652 its children, that is, all its subtests.
653 Note that this function only updates value in skip_map, not the actual
654 test_list tree.
Jon Salz008f4ea2012-08-28 05:39:45 +0800655
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800656 Args:
657 test: The given FactoryTest object. It is a node in the test_list tree.
658 skip_from_parent: The skip value which propagates from the parent of
659 input node.
660 """
661 skip_this_tree = skip_from_parent or skip_map[test.path]
662 if skip_this_tree:
663 logging.info('Skip from node %r', test.path)
664 skip_map[test.path] = True
665 if test.is_leaf():
666 return
667 # Propagates skip value to its subtests
668 for subtest in test.subtests:
669 _update_skip_map_from_node(subtest, skip_this_tree)
670
671 _update_skip_map_from_node(self.test_list, False)
672
673 # Updates the skip value from skip_map to test_list tree. Also, updates test
674 # status if needed.
675 for t in self.test_list.walk():
676 skip = skip_map[t.path]
677 test_state = t.get_state()
678 if ((not skip) and
679 (test_state.status == TestState.PASSED) and
680 (test_state.error_msg == TestState.SKIPPED_MSG)):
681 # It was marked as skipped before, but now we need to run it.
682 # Mark as untested.
683 t.update_state(skip=skip, status=TestState.UNTESTED, error_msg='')
684 else:
685 t.update_state(skip=skip)
Jon Salz008f4ea2012-08-28 05:39:45 +0800686
Jon Salz0697cbf2012-07-04 15:14:04 +0800687 def show_next_active_test(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800688 """Rotates to the next visible active test."""
Jon Salz0697cbf2012-07-04 15:14:04 +0800689 self.reap_completed_tests()
690 active_tests = [
Ricky Liang45c73e72015-01-15 15:00:30 +0800691 t for t in self.test_list.walk()
692 if t.is_leaf() and t.get_state().status == TestState.ACTIVE]
Jon Salz0697cbf2012-07-04 15:14:04 +0800693 if not active_tests:
694 return
Jon Salz4f6c7172012-06-11 20:45:36 +0800695
Jon Salz0697cbf2012-07-04 15:14:04 +0800696 try:
697 next_test = active_tests[
Ricky Liang45c73e72015-01-15 15:00:30 +0800698 (active_tests.index(self.visible_test) + 1) % len(active_tests)]
Jon Salz0697cbf2012-07-04 15:14:04 +0800699 except ValueError: # visible_test not present in active_tests
700 next_test = active_tests[0]
Jon Salz4f6c7172012-06-11 20:45:36 +0800701
Jon Salz0697cbf2012-07-04 15:14:04 +0800702 self.set_visible_test(next_test)
Jon Salz4f6c7172012-06-11 20:45:36 +0800703
Jon Salz0697cbf2012-07-04 15:14:04 +0800704 def handle_event(self, event):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800705 """Handles an event from the event server."""
Jon Salz0697cbf2012-07-04 15:14:04 +0800706 handler = self.event_handlers.get(event.type)
707 if handler:
708 handler(event)
709 else:
710 # We don't register handlers for all event types - just ignore
711 # this event.
712 logging.debug('Unbound event type %s', event.type)
Jon Salz4f6c7172012-06-11 20:45:36 +0800713
Vic Yangaabf9fd2013-04-09 18:56:13 +0800714 def check_critical_factory_note(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800715 """Returns True if the last factory note is critical."""
Vic Yangaabf9fd2013-04-09 18:56:13 +0800716 notes = self.state_instance.get_shared_data('factory_note', True)
717 return notes and notes[-1]['level'] == 'CRITICAL'
718
Jon Salz0697cbf2012-07-04 15:14:04 +0800719 def run_next_test(self):
henryhsu4cc6b022014-04-22 17:12:42 +0800720 """Runs the next eligible test (or tests) in self.tests_to_run.
721
722 We have three kinds of the next eligible test:
723 1. normal
724 2. backgroundable
725 3. force_background
726
727 And we have four situations of the ongoing invocations:
728 a. only a running normal test
729 b. all running tests are backgroundable
730 c. all running tests are force_background
731 d. all running tests are any combination of backgroundable and
732 force_background
733
734 When a test would like to be run, it must follow the rules:
735 [1] cannot run with [abd]
736 [2] cannot run with [a]
737 All the other combinations are allowed
738 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800739 self.reap_completed_tests()
Vic Yangaabf9fd2013-04-09 18:56:13 +0800740 if self.tests_to_run and self.check_critical_factory_note():
741 self.tests_to_run.clear()
742 return
Jon Salz0697cbf2012-07-04 15:14:04 +0800743 while self.tests_to_run:
Ricky Liang6fe218c2013-12-27 15:17:17 +0800744 logging.debug('Tests to run: %s', [x.path for x in self.tests_to_run])
Jon Salz94eb56f2012-06-12 18:01:12 +0800745
Jon Salz0697cbf2012-07-04 15:14:04 +0800746 test = self.tests_to_run[0]
Jon Salz94eb56f2012-06-12 18:01:12 +0800747
Jon Salz0697cbf2012-07-04 15:14:04 +0800748 if test in self.invocations:
749 logging.info('Next test %s is already running', test.path)
750 self.tests_to_run.popleft()
751 return
Jon Salz94eb56f2012-06-12 18:01:12 +0800752
Jon Salza1412922012-07-23 16:04:17 +0800753 for requirement in test.require_run:
754 for i in requirement.test.walk():
755 if i.get_state().status == TestState.ACTIVE:
Jon Salz304a75d2012-07-06 11:14:15 +0800756 logging.info('Waiting for active test %s to complete '
Jon Salza1412922012-07-23 16:04:17 +0800757 'before running %s', i.path, test.path)
Jon Salz304a75d2012-07-06 11:14:15 +0800758 return
759
henryhsu4cc6b022014-04-22 17:12:42 +0800760 def is_normal_test(test):
761 return not (test.backgroundable or test.force_background)
762
763 # [1] cannot run with [abd].
764 if self.invocations and is_normal_test(test) and any(
765 [not x.force_background for x in self.invocations]):
766 logging.info('Waiting for non-force_background tests to '
767 'complete before running %s', test.path)
768 return
769
770 # [2] cannot run with [a].
771 if self.invocations and test.backgroundable and any(
772 [is_normal_test(x) for x in self.invocations]):
773 logging.info('Waiting for normal tests to '
774 'complete before running %s', test.path)
Jon Salz0697cbf2012-07-04 15:14:04 +0800775 return
Jon Salz94eb56f2012-06-12 18:01:12 +0800776
Jon Salz3e6f5202012-10-15 15:08:29 +0800777 if test.get_state().skip:
778 factory.console.info('Skipping test %s', test.path)
779 test.update_state(status=TestState.PASSED,
780 error_msg=TestState.SKIPPED_MSG)
781 self.tests_to_run.popleft()
782 continue
783
Jon Salz0697cbf2012-07-04 15:14:04 +0800784 self.tests_to_run.popleft()
Jon Salz94eb56f2012-06-12 18:01:12 +0800785
Jon Salz304a75d2012-07-06 11:14:15 +0800786 untested = set()
Jon Salza1412922012-07-23 16:04:17 +0800787 for requirement in test.require_run:
788 for i in requirement.test.walk():
789 if i == test:
Jon Salz304a75d2012-07-06 11:14:15 +0800790 # We've hit this test itself; stop checking
791 break
Jon Salza1412922012-07-23 16:04:17 +0800792 if ((i.get_state().status == TestState.UNTESTED) or
793 (requirement.passed and i.get_state().status !=
794 TestState.PASSED)):
Jon Salz304a75d2012-07-06 11:14:15 +0800795 # Found an untested test; move on to the next
796 # element in require_run.
Jon Salza1412922012-07-23 16:04:17 +0800797 untested.add(i)
Jon Salz304a75d2012-07-06 11:14:15 +0800798 break
799
800 if untested:
801 untested_paths = ', '.join(sorted([x.path for x in untested]))
802 if self.state_instance.get_shared_data('engineering_mode',
803 optional=True):
804 # In engineering mode, we'll let it go.
805 factory.console.warn('In engineering mode; running '
806 '%s even though required tests '
807 '[%s] have not completed',
808 test.path, untested_paths)
809 else:
810 # Not in engineering mode; mark it failed.
811 error_msg = ('Required tests [%s] have not been run yet'
812 % untested_paths)
813 factory.console.error('Not running %s: %s',
814 test.path, error_msg)
815 test.update_state(status=TestState.FAILED,
816 error_msg=error_msg)
817 continue
818
Ricky Liang48e47f92014-02-26 19:31:51 +0800819 if (isinstance(test, factory.ShutdownStep) and
Ricky Liangb7eb8772014-09-15 18:05:22 +0800820 self.state_instance.get_shared_data(
821 state.POST_SHUTDOWN_TAG % test.path, optional=True)):
Ricky Liang48e47f92014-02-26 19:31:51 +0800822 # Invoking post shutdown method of shutdown test. We should retain the
823 # iterations_left and retries_left of the original test state.
824 test_state = self.state_instance.get_test_state(test.path)
825 self._run_test(test, test_state.iterations_left,
826 test_state.retries_left)
827 else:
828 # Starts a new test run; reset iterations and retries.
829 self._run_test(test, test.iterations, test.retries)
Jon Salz1acc8742012-07-17 17:45:55 +0800830
Cheng-Yi Chiangce05c002013-04-04 02:13:17 +0800831 def _run_test(self, test, iterations_left=None, retries_left=None):
Vic Yanga3cecf82014-12-26 00:44:21 -0800832 if not self._ui_initialized and not test.is_no_host():
833 self.init_ui()
Vic Yang08505c72015-01-06 17:01:53 -0800834 invoc = TestInvocation(
835 self, test, on_completion=self.run_next_test,
836 on_test_failure=system.GetBoard().OnTestFailure)
Jon Salz1acc8742012-07-17 17:45:55 +0800837 new_state = test.update_state(
Ricky Liang48e47f92014-02-26 19:31:51 +0800838 status=TestState.ACTIVE, increment_count=1, error_msg='',
839 invocation=invoc.uuid, iterations_left=iterations_left,
840 retries_left=retries_left,
841 visible=(self.visible_test == test))
Jon Salz1acc8742012-07-17 17:45:55 +0800842 invoc.count = new_state.count
843
844 self.invocations[test] = invoc
845 if self.visible_test is None and test.has_ui:
846 self.set_visible_test(test)
Vic Yang311ddb82012-09-26 12:08:28 +0800847 self.check_exclusive()
Jon Salz1acc8742012-07-17 17:45:55 +0800848 invoc.start()
Jon Salz5f2a0672012-05-22 17:14:06 +0800849
Vic Yang311ddb82012-09-26 12:08:28 +0800850 def check_exclusive(self):
Jon Salzce6a7f82013-06-10 18:22:54 +0800851 # alias since this is really long
852 EXCL_OPT = factory.FactoryTest.EXCLUSIVE_OPTIONS
853
Vic Yang311ddb82012-09-26 12:08:28 +0800854 current_exclusive_items = set([
Jon Salzce6a7f82013-06-10 18:22:54 +0800855 item for item in EXCL_OPT
Vic Yang311ddb82012-09-26 12:08:28 +0800856 if any([test.is_exclusive(item) for test in self.invocations])])
857
858 new_exclusive_items = current_exclusive_items - self.exclusive_items
Jon Salzce6a7f82013-06-10 18:22:54 +0800859 if EXCL_OPT.NETWORKING in new_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800860 logging.info('Disabling network')
861 self.connection_manager.DisableNetworking()
Jon Salzce6a7f82013-06-10 18:22:54 +0800862 if EXCL_OPT.CHARGER in new_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800863 logging.info('Stop controlling charger')
864
865 new_non_exclusive_items = self.exclusive_items - current_exclusive_items
Jon Salzce6a7f82013-06-10 18:22:54 +0800866 if EXCL_OPT.NETWORKING in new_non_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800867 logging.info('Re-enabling network')
868 self.connection_manager.EnableNetworking()
Jon Salzce6a7f82013-06-10 18:22:54 +0800869 if EXCL_OPT.CHARGER in new_non_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800870 logging.info('Start controlling charger')
871
Jon Salzce6a7f82013-06-10 18:22:54 +0800872 if self.cpufreq_manager:
873 enabled = EXCL_OPT.CPUFREQ not in current_exclusive_items
874 try:
875 self.cpufreq_manager.SetEnabled(enabled)
876 except: # pylint: disable=W0702
877 logging.exception('Unable to %s cpufreq services',
878 'enable' if enabled else 'disable')
879
Ricky Liang0f9978e2015-01-30 08:19:17 +0000880 # Only adjust charge state if not excluded
881 if (EXCL_OPT.CHARGER not in current_exclusive_items and
882 not utils.in_chroot()):
883 if self.charge_manager:
Cheng-Yi Chiangd8186952013-04-04 23:41:14 +0800884 self.charge_manager.AdjustChargeState()
885 else:
Dean Liao88b93192014-10-23 19:37:41 +0800886 self.charge()
Vic Yang311ddb82012-09-26 12:08:28 +0800887
888 self.exclusive_items = current_exclusive_items
Jon Salz5da61e62012-05-31 13:06:22 +0800889
Dean Liao88b93192014-10-23 19:37:41 +0800890 def charge(self):
891 """Charges the board.
892
893 It won't try again if last time SetChargeState raised an exception.
894 """
895 if not self._can_charge:
896 return
897
898 try:
Ricky Liang9ac35e02015-01-30 16:01:32 +0800899 if self.charge_manager:
900 self.charge_manager.StartCharging()
901 else:
902 system.GetBoard().SetChargeState(Board.ChargeState.CHARGE)
Dean Liao88b93192014-10-23 19:37:41 +0800903 except NotImplementedError:
904 logging.info('Charging is not supported')
905 self._can_charge = False
906 except BoardException:
907 logging.exception('Unable to set charge state on this board')
908 self._can_charge = False
909
cychiang21886742012-07-05 15:16:32 +0800910 def check_for_updates(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800911 """Schedules an asynchronous check for updates if necessary."""
cychiang21886742012-07-05 15:16:32 +0800912 if not self.test_list.options.update_period_secs:
913 # Not enabled.
914 return
915
916 now = time.time()
917 if self.last_update_check and (
918 now - self.last_update_check <
919 self.test_list.options.update_period_secs):
920 # Not yet time for another check.
921 return
922
923 self.last_update_check = now
924
925 def handle_check_for_update(reached_shopfloor, md5sum, needs_update):
926 if reached_shopfloor:
927 new_update_md5sum = md5sum if needs_update else None
928 if system.SystemInfo.update_md5sum != new_update_md5sum:
929 logging.info('Received new update MD5SUM: %s', new_update_md5sum)
930 system.SystemInfo.update_md5sum = new_update_md5sum
Peter Ammon1e1ec572014-06-26 17:56:32 -0700931 self.run_enqueue(self.update_system_info)
cychiang21886742012-07-05 15:16:32 +0800932
933 updater.CheckForUpdateAsync(
Ricky Liang45c73e72015-01-15 15:00:30 +0800934 handle_check_for_update,
935 self.test_list.options.shopfloor_timeout_secs)
cychiang21886742012-07-05 15:16:32 +0800936
Jon Salza6711d72012-07-18 14:33:03 +0800937 def cancel_pending_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800938 """Cancels any tests in the run queue."""
Jon Salza6711d72012-07-18 14:33:03 +0800939 self.run_tests([])
940
Ricky Liang4bff3e32014-02-20 18:46:11 +0800941 def restore_active_run_state(self):
942 """Restores active run id and the list of scheduled tests."""
943 self.run_id = self.state_instance.get_shared_data('run_id', optional=True)
944 self.scheduled_run_tests = self.state_instance.get_shared_data(
945 'scheduled_run_tests', optional=True)
946
947 def set_active_run_state(self):
948 """Sets active run id and the list of scheduled tests."""
949 self.run_id = str(uuid.uuid4())
950 self.scheduled_run_tests = [test.path for test in self.tests_to_run]
951 self.state_instance.set_shared_data('run_id', self.run_id)
952 self.state_instance.set_shared_data('scheduled_run_tests',
953 self.scheduled_run_tests)
954
Jon Salz0697cbf2012-07-04 15:14:04 +0800955 def run_tests(self, subtrees, untested_only=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800956 """Runs tests under subtree.
Jon Salz258a40c2012-04-19 12:34:01 +0800957
Jon Salz0697cbf2012-07-04 15:14:04 +0800958 The tests are run in order unless one fails (then stops).
959 Backgroundable tests are run simultaneously; when a foreground test is
960 encountered, we wait for all active tests to finish before continuing.
Jon Salzb1b39092012-05-03 02:05:09 +0800961
Ricky Liang6fe218c2013-12-27 15:17:17 +0800962 Args:
963 subtrees: Node or nodes containing tests to run (may either be
964 a single test or a list). Duplicates will be ignored.
965 untested_only: True to run untested tests only.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800966 """
Vic Yang08505c72015-01-06 17:01:53 -0800967 system.GetBoard().OnTestStart()
968
Jon Salz0697cbf2012-07-04 15:14:04 +0800969 if type(subtrees) != list:
970 subtrees = [subtrees]
Jon Salz258a40c2012-04-19 12:34:01 +0800971
Jon Salz0697cbf2012-07-04 15:14:04 +0800972 # Nodes we've seen so far, to avoid duplicates.
973 seen = set()
Jon Salz94eb56f2012-06-12 18:01:12 +0800974
Jon Salz0697cbf2012-07-04 15:14:04 +0800975 self.tests_to_run = deque()
976 for subtree in subtrees:
977 for test in subtree.walk():
978 if test in seen:
979 continue
980 seen.add(test)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800981
Jon Salz0697cbf2012-07-04 15:14:04 +0800982 if not test.is_leaf():
983 continue
Ricky Liang45c73e72015-01-15 15:00:30 +0800984 if untested_only and test.get_state().status != TestState.UNTESTED:
Jon Salz0697cbf2012-07-04 15:14:04 +0800985 continue
986 self.tests_to_run.append(test)
Ricky Liang4bff3e32014-02-20 18:46:11 +0800987 if subtrees:
988 self.set_active_run_state()
Jon Salz0697cbf2012-07-04 15:14:04 +0800989 self.run_next_test()
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800990
Jon Salz0697cbf2012-07-04 15:14:04 +0800991 def reap_completed_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800992 """Removes completed tests from the set of active tests.
Jon Salz0697cbf2012-07-04 15:14:04 +0800993
994 Also updates the visible test if it was reaped.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800995 """
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +0800996 test_completed = False
Jon Salz0697cbf2012-07-04 15:14:04 +0800997 for t, v in dict(self.invocations).iteritems():
998 if v.is_completed():
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +0800999 test_completed = True
Jon Salz1acc8742012-07-17 17:45:55 +08001000 new_state = t.update_state(**v.update_state_on_completion)
Jon Salz0697cbf2012-07-04 15:14:04 +08001001 del self.invocations[t]
1002
Chun-Ta Lin54e17e42012-09-06 22:05:13 +08001003 # Stop on failure if flag is true.
1004 if (self.test_list.options.stop_on_failure and
1005 new_state.status == TestState.FAILED):
1006 # Clean all the tests to cause goofy to stop.
1007 self.tests_to_run = []
Ricky Liang45c73e72015-01-15 15:00:30 +08001008 factory.console.info('Stop on failure triggered. Empty the queue.')
Chun-Ta Lin54e17e42012-09-06 22:05:13 +08001009
Jon Salz1acc8742012-07-17 17:45:55 +08001010 if new_state.iterations_left and new_state.status == TestState.PASSED:
1011 # Play it again, Sam!
1012 self._run_test(t)
Cheng-Yi Chiangce05c002013-04-04 02:13:17 +08001013 # new_state.retries_left is obtained after update.
1014 # For retries_left == 0, test can still be run for the last time.
1015 elif (new_state.retries_left >= 0 and
1016 new_state.status == TestState.FAILED):
1017 # Still have to retry, Sam!
1018 self._run_test(t)
Jon Salz1acc8742012-07-17 17:45:55 +08001019
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001020 if test_completed:
Vic Yangf01c59f2013-04-19 17:37:56 +08001021 self.log_watcher.KickWatchThread()
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001022
Jon Salz0697cbf2012-07-04 15:14:04 +08001023 if (self.visible_test is None or
Jon Salz85a39882012-07-05 16:45:04 +08001024 self.visible_test not in self.invocations):
Jon Salz0697cbf2012-07-04 15:14:04 +08001025 self.set_visible_test(None)
1026 # Make the first running test, if any, the visible test
1027 for t in self.test_list.walk():
1028 if t in self.invocations:
1029 self.set_visible_test(t)
1030 break
1031
Jon Salz6dc031d2013-06-19 13:06:23 +08001032 def kill_active_tests(self, abort, root=None, reason=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001033 """Kills and waits for all active tests.
Jon Salz0697cbf2012-07-04 15:14:04 +08001034
Jon Salz85a39882012-07-05 16:45:04 +08001035 Args:
1036 abort: True to change state of killed tests to FAILED, False for
Jon Salz0697cbf2012-07-04 15:14:04 +08001037 UNTESTED.
Jon Salz85a39882012-07-05 16:45:04 +08001038 root: If set, only kills tests with root as an ancestor.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001039 reason: If set, the abort reason.
1040 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001041 self.reap_completed_tests()
1042 for test, invoc in self.invocations.items():
Jon Salz85a39882012-07-05 16:45:04 +08001043 if root and not test.has_ancestor(root):
1044 continue
1045
Ricky Liang45c73e72015-01-15 15:00:30 +08001046 factory.console.info('Killing active test %s...', test.path)
Jon Salz6dc031d2013-06-19 13:06:23 +08001047 invoc.abort_and_join(reason)
Ricky Liang45c73e72015-01-15 15:00:30 +08001048 factory.console.info('Killed %s', test.path)
Jon Salz1acc8742012-07-17 17:45:55 +08001049 test.update_state(**invoc.update_state_on_completion)
Jon Salz0697cbf2012-07-04 15:14:04 +08001050 del self.invocations[test]
Jon Salz1acc8742012-07-17 17:45:55 +08001051
Jon Salz0697cbf2012-07-04 15:14:04 +08001052 if not abort:
1053 test.update_state(status=TestState.UNTESTED)
1054 self.reap_completed_tests()
1055
Jon Salz6dc031d2013-06-19 13:06:23 +08001056 def stop(self, root=None, fail=False, reason=None):
1057 self.kill_active_tests(fail, root, reason)
Jon Salz85a39882012-07-05 16:45:04 +08001058 # Remove any tests in the run queue under the root.
1059 self.tests_to_run = deque([x for x in self.tests_to_run
1060 if root and not x.has_ancestor(root)])
1061 self.run_next_test()
Jon Salz0697cbf2012-07-04 15:14:04 +08001062
Jon Salz4712ac72013-02-07 17:12:05 +08001063 def clear_state(self, root=None):
Jon Salzd7550792013-07-12 05:49:27 +08001064 if root is None:
1065 root = self.test_list
Jon Salz6dc031d2013-06-19 13:06:23 +08001066 self.stop(root, reason='Clearing test state')
Jon Salz4712ac72013-02-07 17:12:05 +08001067 for f in root.walk():
1068 if f.is_leaf():
1069 f.update_state(status=TestState.UNTESTED)
1070
Jon Salz6dc031d2013-06-19 13:06:23 +08001071 def abort_active_tests(self, reason=None):
1072 self.kill_active_tests(True, reason=reason)
Jon Salz0697cbf2012-07-04 15:14:04 +08001073
1074 def main(self):
Jon Salzeff94182013-06-19 15:06:28 +08001075 syslog.openlog('goofy')
1076
Jon Salz0697cbf2012-07-04 15:14:04 +08001077 try:
Jon Salzd7550792013-07-12 05:49:27 +08001078 self.status = Status.INITIALIZING
Jon Salz0697cbf2012-07-04 15:14:04 +08001079 self.init()
1080 self.event_log.Log('goofy_init',
Ricky Liang45c73e72015-01-15 15:00:30 +08001081 success=True)
Jon Salz0697cbf2012-07-04 15:14:04 +08001082 except:
1083 if self.event_log:
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001084 try:
Jon Salz0697cbf2012-07-04 15:14:04 +08001085 self.event_log.Log('goofy_init',
Ricky Liang45c73e72015-01-15 15:00:30 +08001086 success=False,
1087 trace=traceback.format_exc())
Jon Salz0697cbf2012-07-04 15:14:04 +08001088 except: # pylint: disable=W0702
1089 pass
1090 raise
1091
Jon Salzd7550792013-07-12 05:49:27 +08001092 self.status = Status.RUNNING
Jon Salzeff94182013-06-19 15:06:28 +08001093 syslog.syslog('Goofy (factory test harness) starting')
Jon Salz0697cbf2012-07-04 15:14:04 +08001094 self.run()
1095
1096 def update_system_info(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001097 """Updates system info."""
Jon Salz0697cbf2012-07-04 15:14:04 +08001098 system_info = system.SystemInfo()
1099 self.state_instance.set_shared_data('system_info', system_info.__dict__)
1100 self.event_client.post_event(Event(Event.Type.SYSTEM_INFO,
Ricky Liang45c73e72015-01-15 15:00:30 +08001101 system_info=system_info.__dict__))
Jon Salz0697cbf2012-07-04 15:14:04 +08001102 logging.info('System info: %r', system_info.__dict__)
1103
Jon Salzeb42f0d2012-07-27 19:14:04 +08001104 def update_factory(self, auto_run_on_restart=False, post_update_hook=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001105 """Commences updating factory software.
Jon Salzeb42f0d2012-07-27 19:14:04 +08001106
1107 Args:
1108 auto_run_on_restart: Auto-run when the machine comes back up.
1109 post_update_hook: Code to call after update but immediately before
1110 restart.
1111
1112 Returns:
1113 Never if the update was successful (we just reboot).
1114 False if the update was unnecessary (no update available).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001115 """
Jon Salz6dc031d2013-06-19 13:06:23 +08001116 self.kill_active_tests(False, reason='Factory software update')
Jon Salza6711d72012-07-18 14:33:03 +08001117 self.cancel_pending_tests()
Jon Salz0697cbf2012-07-04 15:14:04 +08001118
Jon Salz5c344f62012-07-13 14:31:16 +08001119 def pre_update_hook():
1120 if auto_run_on_restart:
1121 self.state_instance.set_shared_data('tests_after_shutdown',
1122 FORCE_AUTO_RUN)
1123 self.state_instance.close()
1124
Jon Salzeb42f0d2012-07-27 19:14:04 +08001125 if updater.TryUpdate(pre_update_hook=pre_update_hook):
1126 if post_update_hook:
1127 post_update_hook()
1128 self.env.shutdown('reboot')
Jon Salz0697cbf2012-07-04 15:14:04 +08001129
Ricky Liang8fecf412014-05-22 10:56:14 +08001130 def handle_sigint(self, dummy_signum, dummy_frame): # pylint: disable=W0613
Jon Salz77c151e2012-08-28 07:20:37 +08001131 logging.error('Received SIGINT')
Peter Ammon1e1ec572014-06-26 17:56:32 -07001132 self.run_enqueue(None)
Jon Salz77c151e2012-08-28 07:20:37 +08001133 raise KeyboardInterrupt()
1134
Ricky Liang8fecf412014-05-22 10:56:14 +08001135 def handle_sigterm(self, dummy_signum, dummy_frame): # pylint: disable=W0613
1136 logging.error('Received SIGTERM')
Hung-Te Lin94ca4742014-07-09 20:13:50 +08001137 self.env.terminate()
1138 self.run_queue.put(None)
Ricky Liang8fecf412014-05-22 10:56:14 +08001139 raise RuntimeError('Received SIGTERM')
1140
Jon Salze12c2b32013-06-25 16:24:34 +08001141 def find_kcrashes(self):
1142 """Finds kcrash files, logs them, and marks them as seen."""
1143 seen_crashes = set(
1144 self.state_instance.get_shared_data('seen_crashes', optional=True)
1145 or [])
1146
1147 for path in glob.glob('/var/spool/crash/*'):
1148 if not os.path.isfile(path):
1149 continue
1150 if path in seen_crashes:
1151 continue
1152 try:
1153 stat = os.stat(path)
1154 mtime = utils.TimeString(stat.st_mtime)
1155 logging.info(
1156 'Found new crash file %s (%d bytes at %s)',
1157 path, stat.st_size, mtime)
1158 extra_log_args = {}
1159
1160 try:
1161 _, ext = os.path.splitext(path)
1162 if ext in ['.kcrash', '.meta']:
1163 ext = ext.replace('.', '')
1164 with open(path) as f:
1165 data = f.read(MAX_CRASH_FILE_SIZE)
1166 tell = f.tell()
1167 logging.info(
1168 'Contents of %s%s:%s',
1169 path,
1170 ('' if tell == stat.st_size
1171 else '(truncated to %d bytes)' % MAX_CRASH_FILE_SIZE),
1172 ('\n' + data).replace('\n', '\n ' + ext + '> '))
1173 extra_log_args['data'] = data
1174
1175 # Copy to /var/factory/kcrash for posterity
1176 kcrash_dir = factory.get_factory_root('kcrash')
1177 utils.TryMakeDirs(kcrash_dir)
1178 shutil.copy(path, kcrash_dir)
1179 logging.info('Copied to %s',
1180 os.path.join(kcrash_dir, os.path.basename(path)))
1181 finally:
1182 # Even if something goes wrong with the above, still try to
1183 # log to event log
1184 self.event_log.Log('crash_file',
1185 path=path, size=stat.st_size, mtime=mtime,
1186 **extra_log_args)
1187 except: # pylint: disable=W0702
1188 logging.exception('Unable to handle crash files %s', path)
1189 seen_crashes.add(path)
1190
1191 self.state_instance.set_shared_data('seen_crashes', list(seen_crashes))
1192
Jon Salz128b0932013-07-03 16:55:26 +08001193 def GetTestList(self, test_list_id):
1194 """Returns the test list with the given ID.
1195
1196 Raises:
1197 TestListError: The test list ID is not valid.
1198 """
1199 try:
1200 return self.test_lists[test_list_id]
1201 except KeyError:
1202 raise test_lists.TestListError(
1203 '%r is not a valid test list ID (available IDs are [%s])' % (
1204 test_list_id, ', '.join(sorted(self.test_lists.keys()))))
1205
1206 def InitTestLists(self):
1207 """Reads in all test lists and sets the active test list."""
Ricky Liang27051552014-05-04 14:22:26 +08001208 self.test_lists = test_lists.BuildAllTestLists(
1209 force_generic=(self.options.automation_mode is not None))
Jon Salzd7550792013-07-12 05:49:27 +08001210 logging.info('Loaded test lists: [%s]',
1211 test_lists.DescribeTestLists(self.test_lists))
Jon Salz128b0932013-07-03 16:55:26 +08001212
1213 if not self.options.test_list:
1214 self.options.test_list = test_lists.GetActiveTestListId()
1215
1216 if os.sep in self.options.test_list:
1217 # It's a path pointing to an old-style test list; use it.
1218 self.test_list = factory.read_test_list(self.options.test_list)
1219 else:
1220 self.test_list = self.GetTestList(self.options.test_list)
1221
1222 logging.info('Active test list: %s', self.test_list.test_list_id)
1223
1224 if isinstance(self.test_list, test_lists.OldStyleTestList):
1225 # Actually load it in. (See OldStyleTestList for an explanation
1226 # of why this is necessary.)
1227 self.test_list = self.test_list.Load()
1228
1229 self.test_list.state_instance = self.state_instance
1230
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001231 def init_hooks(self):
1232 """Initializes hooks.
1233
1234 Must run after self.test_list ready.
1235 """
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001236 module, cls = self.test_list.options.hooks_class.rsplit('.', 1)
1237 self.hooks = getattr(__import__(module, fromlist=[cls]), cls)()
1238 assert isinstance(self.hooks, factory.Hooks), (
Ricky Liang45c73e72015-01-15 15:00:30 +08001239 'hooks should be of type Hooks but is %r' % type(self.hooks))
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001240 self.hooks.test_list = self.test_list
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001241 self.hooks.OnCreatedTestList()
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001242
Vic Yanga3cecf82014-12-26 00:44:21 -08001243 def init_ui(self):
1244 """Initialize UI."""
1245 self._ui_initialized = True
1246 if self.options.ui == 'chrome':
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001247 if self.options.monolithic:
Hung-Te Lin7bd55312014-12-30 16:43:36 +08001248 self.env.launch_chrome()
1249 else:
1250 # The presenter is responsible for launching Chrome. Let's just
1251 # wait here.
1252 self.env.controller_ready_for_ui()
Vic Yanga3cecf82014-12-26 00:44:21 -08001253 logging.info('Waiting for a web socket connection')
1254 self.web_socket_manager.wait()
1255
1256 # Wait for the test widget size to be set; this is done in
1257 # an asynchronous RPC so there is a small chance that the
1258 # web socket might be opened first.
1259 for _ in range(100): # 10 s
1260 try:
1261 if self.state_instance.get_shared_data('test_widget_size'):
1262 break
1263 except KeyError:
1264 pass # Retry
1265 time.sleep(0.1) # 100 ms
1266 else:
1267 logging.warn('Never received test_widget_size from UI')
1268
Hung-Te Lin7bd55312014-12-30 16:43:36 +08001269 logging.info('Waiting for a web socket connection')
1270 self.web_socket_manager.wait()
1271
Jon Salz0697cbf2012-07-04 15:14:04 +08001272 def init(self, args=None, env=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001273 """Initializes Goofy.
Jon Salz0697cbf2012-07-04 15:14:04 +08001274
1275 Args:
1276 args: A list of command-line arguments. Uses sys.argv if
1277 args is None.
1278 env: An Environment instance to use (or None to choose
1279 FakeChrootEnvironment or DUTEnvironment as appropriate).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001280 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001281 parser = OptionParser()
1282 parser.add_option('-v', '--verbose', dest='verbose',
Jon Salz8fa8e832012-07-13 19:04:09 +08001283 action='store_true',
1284 help='Enable debug logging')
Jon Salz0697cbf2012-07-04 15:14:04 +08001285 parser.add_option('--print_test_list', dest='print_test_list',
Jon Salz8fa8e832012-07-13 19:04:09 +08001286 metavar='FILE',
1287 help='Read and print test list FILE, and exit')
Jon Salz0697cbf2012-07-04 15:14:04 +08001288 parser.add_option('--restart', dest='restart',
Jon Salz8fa8e832012-07-13 19:04:09 +08001289 action='store_true',
1290 help='Clear all test state')
Jon Salz0697cbf2012-07-04 15:14:04 +08001291 parser.add_option('--ui', dest='ui', type='choice',
Jon Salz7b5482e2014-08-04 17:48:41 +08001292 choices=['none', 'chrome'],
Jon Salz2f881df2013-02-01 17:00:35 +08001293 default='chrome',
Jon Salz8fa8e832012-07-13 19:04:09 +08001294 help='UI to use')
Jon Salz0697cbf2012-07-04 15:14:04 +08001295 parser.add_option('--ui_scale_factor', dest='ui_scale_factor',
Jon Salz8fa8e832012-07-13 19:04:09 +08001296 type='int', default=1,
1297 help=('Factor by which to scale UI '
1298 '(Chrome UI only)'))
Jon Salz0697cbf2012-07-04 15:14:04 +08001299 parser.add_option('--test_list', dest='test_list',
Jon Salz8fa8e832012-07-13 19:04:09 +08001300 metavar='FILE',
1301 help='Use FILE as test list')
Jon Salzc79a9982012-08-30 04:42:01 +08001302 parser.add_option('--dummy_shopfloor', action='store_true',
1303 help='Use a dummy shopfloor server')
Hung-Te Lincc41d2a2014-10-29 13:35:20 +08001304 parser.add_option('--dummy_connection_manager', action='store_true',
1305 help='Use a dummy connection manager')
Ricky Liang6fe218c2013-12-27 15:17:17 +08001306 parser.add_option('--automation-mode',
1307 choices=[m.lower() for m in AutomationMode],
Ricky Liang45c73e72015-01-15 15:00:30 +08001308 default='none', help='Factory test automation mode.')
Ricky Liang117484a2014-04-14 11:14:41 +08001309 parser.add_option('--no-auto-run-on-start', dest='auto_run_on_start',
1310 action='store_false', default=True,
1311 help=('do not automatically run the test list on goofy '
1312 'start; this is only valid when factory test '
1313 'automation is enabled'))
Chun-Ta Lina8dd3172014-11-26 16:15:13 +08001314 parser.add_option('--handshake_timeout', dest='handshake_timeout',
1315 type='float', default=0.3,
1316 help=('RPC timeout when doing handshake between device '
1317 'and presenter.'))
Vic Yang7d693c42014-09-14 09:52:39 +08001318 parser.add_option('--standalone', dest='standalone',
1319 action='store_true', default=False,
1320 help=('Assume the presenter is running on the same '
1321 'machines.'))
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001322 parser.add_option('--monolithic', dest='monolithic',
1323 action='store_true', default=False,
1324 help='Run in monolithic mode (without presenter)')
Jon Salz0697cbf2012-07-04 15:14:04 +08001325 (self.options, self.args) = parser.parse_args(args)
1326
Hung-Te Lina846f602014-07-04 20:32:22 +08001327 signal.signal(signal.SIGINT, self.handle_sigint)
1328 # TODO(hungte) SIGTERM does not work properly without Telemetry and should
1329 # be fixed.
Hung-Te Lina846f602014-07-04 20:32:22 +08001330
Jon Salz46b89562012-07-05 11:49:22 +08001331 # Make sure factory directories exist.
1332 factory.get_log_root()
1333 factory.get_state_root()
1334 factory.get_test_data_root()
1335
Jon Salz0697cbf2012-07-04 15:14:04 +08001336 global _inited_logging # pylint: disable=W0603
1337 if not _inited_logging:
1338 factory.init_logging('goofy', verbose=self.options.verbose)
1339 _inited_logging = True
Jon Salz8fa8e832012-07-13 19:04:09 +08001340
Jon Salz0f996602012-10-03 15:26:48 +08001341 if self.options.print_test_list:
Joel Kitchingb85ed7f2014-10-08 18:24:39 +08001342 print(factory.read_test_list(
1343 self.options.print_test_list).__repr__(recursive=True))
Jon Salz0f996602012-10-03 15:26:48 +08001344 sys.exit(0)
1345
Jon Salzee85d522012-07-17 14:34:46 +08001346 event_log.IncrementBootSequence()
Jon Salzd15bbcf2013-05-21 17:33:57 +08001347 # Don't defer logging the initial event, so we can make sure
1348 # that device_id, reimage_id, etc. are all set up.
1349 self.event_log = EventLog('goofy', defer=False)
Jon Salz0697cbf2012-07-04 15:14:04 +08001350
Jon Salz0697cbf2012-07-04 15:14:04 +08001351 if env:
1352 self.env = env
1353 elif factory.in_chroot():
1354 self.env = test_environment.FakeChrootEnvironment()
1355 logging.warn(
Ricky Liang45c73e72015-01-15 15:00:30 +08001356 'Using chroot environment: will not actually run autotests')
Hung-Te Lina846f602014-07-04 20:32:22 +08001357 elif self.options.ui == 'chrome':
Ricky Liang09d66d82014-09-25 11:20:54 +08001358 self.env = test_environment.DUTEnvironment()
Jon Salz0697cbf2012-07-04 15:14:04 +08001359 self.env.goofy = self
Vic Yanga4931152014-08-11 16:36:24 -07001360 # web_socket_manager will be initialized later
1361 # pylint: disable=W0108
1362 self.env.has_sockets = lambda: self.web_socket_manager.has_sockets()
Jon Salz0697cbf2012-07-04 15:14:04 +08001363
1364 if self.options.restart:
1365 state.clear_state()
1366
Jon Salz0697cbf2012-07-04 15:14:04 +08001367 if self.options.ui_scale_factor != 1 and utils.in_qemu():
1368 logging.warn(
Ricky Liang45c73e72015-01-15 15:00:30 +08001369 'In QEMU; ignoring ui_scale_factor argument')
Jon Salz0697cbf2012-07-04 15:14:04 +08001370 self.options.ui_scale_factor = 1
1371
1372 logging.info('Started')
1373
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001374 if not self.options.monolithic:
Hung-Te Lin7bd55312014-12-30 16:43:36 +08001375 self.link_manager = PresenterLinkManager(
1376 check_interval=1,
1377 handshake_timeout=self.options.handshake_timeout,
1378 standalone=self.options.standalone)
Peter Ammon1e1ec572014-06-26 17:56:32 -07001379
Jon Salz0697cbf2012-07-04 15:14:04 +08001380 self.start_state_server()
1381 self.state_instance.set_shared_data('hwid_cfg', get_hwid_cfg())
1382 self.state_instance.set_shared_data('ui_scale_factor',
Ricky Liang09216dc2013-02-22 17:26:45 +08001383 self.options.ui_scale_factor)
Jon Salz0697cbf2012-07-04 15:14:04 +08001384 self.last_shutdown_time = (
Ricky Liang45c73e72015-01-15 15:00:30 +08001385 self.state_instance.get_shared_data('shutdown_time', optional=True))
Jon Salz0697cbf2012-07-04 15:14:04 +08001386 self.state_instance.del_shared_data('shutdown_time', optional=True)
Jon Salzb19ea072013-02-07 16:35:00 +08001387 self.state_instance.del_shared_data('startup_error', optional=True)
Jon Salz0697cbf2012-07-04 15:14:04 +08001388
Ricky Liang6fe218c2013-12-27 15:17:17 +08001389 self.options.automation_mode = ParseAutomationMode(
1390 self.options.automation_mode)
1391 self.state_instance.set_shared_data('automation_mode',
1392 self.options.automation_mode)
1393 self.state_instance.set_shared_data(
1394 'automation_mode_prompt',
1395 AutomationModePrompt[self.options.automation_mode])
1396
Jon Salz128b0932013-07-03 16:55:26 +08001397 try:
1398 self.InitTestLists()
1399 except: # pylint: disable=W0702
1400 logging.exception('Unable to initialize test lists')
1401 self.state_instance.set_shared_data(
1402 'startup_error',
1403 'Unable to initialize test lists\n%s' % (
1404 traceback.format_exc()))
Jon Salzb19ea072013-02-07 16:35:00 +08001405 if self.options.ui == 'chrome':
1406 # Create an empty test list with default options so that the rest of
1407 # startup can proceed.
1408 self.test_list = factory.FactoryTestList(
1409 [], self.state_instance, factory.Options())
1410 else:
1411 # Bail with an error; no point in starting up.
1412 sys.exit('No valid test list; exiting.')
1413
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001414 self.init_hooks()
1415
Jon Salz822838b2013-03-25 17:32:33 +08001416 if self.test_list.options.clear_state_on_start:
1417 self.state_instance.clear_test_state()
1418
Jon Salz670ce062014-05-16 15:53:50 +08001419 # If the phase is invalid, this will raise a ValueError.
1420 phase.SetPersistentPhase(self.test_list.options.phase)
1421
Dean Liao85ca86f2014-11-03 12:28:08 +08001422 # For netboot firmware, mainfw_type should be 'netboot'.
1423 if (system.SystemInfo().mainfw_type != 'nonchrome' and
1424 system.SystemInfo().firmware_version is None):
Ricky Liang45c73e72015-01-15 15:00:30 +08001425 self.state_instance.set_shared_data(
1426 'startup_error',
Vic Yang9bd4f772013-06-04 17:34:00 +08001427 'Netboot firmware detected\n'
1428 'Connect Ethernet and reboot to re-image.\n'
1429 u'侦测到网路开机固件\n'
1430 u'请连接乙太网并重启')
1431
Jon Salz0697cbf2012-07-04 15:14:04 +08001432 if not self.state_instance.has_shared_data('ui_lang'):
1433 self.state_instance.set_shared_data('ui_lang',
Ricky Liang45c73e72015-01-15 15:00:30 +08001434 self.test_list.options.ui_lang)
Jon Salz0697cbf2012-07-04 15:14:04 +08001435 self.state_instance.set_shared_data(
Ricky Liang45c73e72015-01-15 15:00:30 +08001436 'test_list_options',
1437 self.test_list.options.__dict__)
Jon Salz0697cbf2012-07-04 15:14:04 +08001438 self.state_instance.test_list = self.test_list
1439
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001440 self.check_log_rotation()
Jon Salz83ef34b2012-11-01 19:46:35 +08001441
Jon Salz23926422012-09-01 03:38:13 +08001442 if self.options.dummy_shopfloor:
Ricky Liang45c73e72015-01-15 15:00:30 +08001443 os.environ[shopfloor.SHOPFLOOR_SERVER_ENV_VAR_NAME] = (
1444 'http://%s:%d/' %
Joel Kitchingb85ed7f2014-10-08 18:24:39 +08001445 (net_utils.LOCALHOST, shopfloor.DEFAULT_SERVER_PORT))
Jon Salz23926422012-09-01 03:38:13 +08001446 self.dummy_shopfloor = Spawn(
1447 [os.path.join(factory.FACTORY_PATH, 'bin', 'shopfloor_server'),
1448 '--dummy'])
1449 elif self.test_list.options.shopfloor_server_url:
1450 shopfloor.set_server_url(self.test_list.options.shopfloor_server_url)
Jon Salz2bf2f6b2013-03-28 18:49:26 +08001451 shopfloor.set_enabled(True)
Jon Salz23926422012-09-01 03:38:13 +08001452
Jon Salz0f996602012-10-03 15:26:48 +08001453 if self.test_list.options.time_sanitizer and not utils.in_chroot():
Jon Salz8fa8e832012-07-13 19:04:09 +08001454 self.time_sanitizer = time_sanitizer.TimeSanitizer(
Ricky Liang45c73e72015-01-15 15:00:30 +08001455 base_time=time_sanitizer.GetBaseTimeFromFile(
1456 # lsb-factory is written by the factory install shim during
1457 # installation, so it should have a good time obtained from
1458 # the mini-Omaha server. If it's not available, we'll use
1459 # /etc/lsb-factory (which will be much older, but reasonably
1460 # sane) and rely on a shopfloor sync to set a more accurate
1461 # time.
1462 '/usr/local/etc/lsb-factory',
1463 '/etc/lsb-release'))
Jon Salz8fa8e832012-07-13 19:04:09 +08001464 self.time_sanitizer.RunOnce()
1465
Vic Yangd8990da2013-06-27 16:57:43 +08001466 if self.test_list.options.check_cpu_usage_period_secs:
Ricky Liang45c73e72015-01-15 15:00:30 +08001467 self.cpu_usage_watcher = Spawn(
1468 ['py/tools/cpu_usage_monitor.py', '-p',
1469 str(self.test_list.options.check_cpu_usage_period_secs)],
Vic Yangd8990da2013-06-27 16:57:43 +08001470 cwd=factory.FACTORY_PATH)
1471
Jon Salz0697cbf2012-07-04 15:14:04 +08001472 self.init_states()
1473 self.start_event_server()
Wei-Ning Huang38b75f02015-02-25 18:25:14 +08001474 self.start_terminal_server()
Hung-Te Lincc41d2a2014-10-29 13:35:20 +08001475
1476 if self.options.dummy_connection_manager:
1477 # Override network manager creation to dummy implmenetation.
1478 logging.info('Using dummy network manager (--dummy_connection_manager).')
1479 self.connection_manager = connection_manager.DummyConnectionManager()
1480 else:
1481 self.connection_manager = self.env.create_connection_manager(
1482 self.test_list.options.wlans,
1483 self.test_list.options.scan_wifi_period_secs)
1484
Jon Salz0697cbf2012-07-04 15:14:04 +08001485 # Note that we create a log watcher even if
1486 # sync_event_log_period_secs isn't set (no background
1487 # syncing), since we may use it to flush event logs as well.
1488 self.log_watcher = EventLogWatcher(
Ricky Liang45c73e72015-01-15 15:00:30 +08001489 self.test_list.options.sync_event_log_period_secs,
1490 event_log_db_file=None,
1491 handle_event_logs_callback=self.handle_event_logs)
Jon Salz0697cbf2012-07-04 15:14:04 +08001492 if self.test_list.options.sync_event_log_period_secs:
1493 self.log_watcher.StartWatchThread()
1494
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001495 # Creates a system log manager to scan logs periocially.
1496 # A scan includes clearing logs and optionally syncing logs if
1497 # enable_syng_log is True. We kick it to sync logs.
1498 self.system_log_manager = SystemLogManager(
Ricky Liang45c73e72015-01-15 15:00:30 +08001499 sync_log_paths=self.test_list.options.sync_log_paths,
1500 sync_log_period_secs=self.test_list.options.sync_log_period_secs,
1501 scan_log_period_secs=self.test_list.options.scan_log_period_secs,
1502 clear_log_paths=self.test_list.options.clear_log_paths,
1503 clear_log_excluded_paths=self.test_list.options.clear_log_excluded_paths)
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001504 self.system_log_manager.Start()
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +08001505
Jon Salz0697cbf2012-07-04 15:14:04 +08001506 self.update_system_info()
1507
Vic Yang4953fc12012-07-26 16:19:53 +08001508 assert ((self.test_list.options.min_charge_pct is None) ==
1509 (self.test_list.options.max_charge_pct is None))
Vic Yange83d9a12013-04-19 20:00:20 +08001510 if utils.in_chroot():
1511 logging.info('In chroot, ignoring charge manager and charge state')
Ricky Liangc392a1c2014-06-20 18:24:59 +08001512 elif (self.test_list.options.enable_charge_manager and
1513 self.test_list.options.min_charge_pct is not None):
Vic Yang4953fc12012-07-26 16:19:53 +08001514 self.charge_manager = ChargeManager(self.test_list.options.min_charge_pct,
1515 self.test_list.options.max_charge_pct)
Jon Salzad7353b2012-10-15 16:22:46 +08001516 system.SystemStatus.charge_manager = self.charge_manager
Cheng-Yi Chiangd8186952013-04-04 23:41:14 +08001517 else:
1518 # Goofy should set charger state to charge if charge_manager is disabled.
Dean Liao88b93192014-10-23 19:37:41 +08001519 self.charge()
Vic Yang4953fc12012-07-26 16:19:53 +08001520
Vic Yang6cee2472014-10-22 17:18:52 -07001521 if CoreDumpManager.CoreDumpEnabled():
1522 self.core_dump_manager = CoreDumpManager(
1523 self.test_list.options.core_dump_watchlist)
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001524
Jon Salz0697cbf2012-07-04 15:14:04 +08001525 os.environ['CROS_FACTORY'] = '1'
1526 os.environ['CROS_DISABLE_SITE_SYSINFO'] = '1'
1527
Shuo-Peng Liao1ff502e2013-06-30 18:37:02 +08001528 if not utils.in_chroot() and self.test_list.options.use_cpufreq_manager:
Ricky Liangecddbd42014-07-24 11:32:10 +08001529 logging.info('Enabling CPU frequency manager')
Jon Salzddf0d052013-06-18 12:52:44 +08001530 self.cpufreq_manager = CpufreqManager(event_log=self.event_log)
Jon Salzce6a7f82013-06-10 18:22:54 +08001531
Justin Chuang31b02432013-06-27 15:16:51 +08001532 # Startup hooks may want to skip some tests.
1533 self.update_skipped_tests()
Jon Salz416f9cc2013-05-10 18:32:50 +08001534
Jon Salze12c2b32013-06-25 16:24:34 +08001535 self.find_kcrashes()
1536
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001537 # Should not move earlier.
1538 self.hooks.OnStartup()
1539
Ricky Liang36512a32014-07-25 11:47:04 +08001540 # Only after this point the Goofy backend is ready for UI connection.
1541 self.ready_for_ui_connection = True
1542
Ricky Liang650f6bf2012-09-28 13:22:54 +08001543 # Create download path for autotest beforehand or autotests run at
1544 # the same time might fail due to race condition.
1545 if not factory.in_chroot():
1546 utils.TryMakeDirs(os.path.join('/usr/local/autotest', 'tests',
1547 'download'))
1548
Jon Salz0697cbf2012-07-04 15:14:04 +08001549 def state_change_callback(test, test_state):
1550 self.event_client.post_event(
Ricky Liang4bff3e32014-02-20 18:46:11 +08001551 Event(Event.Type.STATE_CHANGE, path=test.path, state=test_state))
Jon Salz0697cbf2012-07-04 15:14:04 +08001552 self.test_list.state_change_callback = state_change_callback
Jon Salz73e0fd02012-04-04 11:46:38 +08001553
Vic Yange2c76a82014-10-30 12:48:19 -07001554 self.autotest_prespawner = prespawner.AutotestPrespawner()
1555 self.autotest_prespawner.start()
1556
1557 self.pytest_prespawner = prespawner.PytestPrespawner()
1558 self.pytest_prespawner.start()
Jon Salza6711d72012-07-18 14:33:03 +08001559
Ricky Liang48e47f92014-02-26 19:31:51 +08001560 tests_after_shutdown = self.state_instance.get_shared_data(
1561 'tests_after_shutdown', optional=True)
Jon Salz57717ca2012-04-04 16:47:25 +08001562
Jon Salz5c344f62012-07-13 14:31:16 +08001563 force_auto_run = (tests_after_shutdown == FORCE_AUTO_RUN)
1564 if not force_auto_run and tests_after_shutdown is not None:
Ricky Liang48e47f92014-02-26 19:31:51 +08001565 logging.info('Resuming tests after shutdown: %s', tests_after_shutdown)
Jon Salz0697cbf2012-07-04 15:14:04 +08001566 self.tests_to_run.extend(
Ricky Liang4bff3e32014-02-20 18:46:11 +08001567 self.test_list.lookup_path(t) for t in tests_after_shutdown)
Peter Ammon1e1ec572014-06-26 17:56:32 -07001568 self.run_enqueue(self.run_next_test)
Jon Salz0697cbf2012-07-04 15:14:04 +08001569 else:
Jon Salz5c344f62012-07-13 14:31:16 +08001570 if force_auto_run or self.test_list.options.auto_run_on_start:
Ricky Liang117484a2014-04-14 11:14:41 +08001571 # If automation mode is enabled, allow suppress auto_run_on_start.
1572 if (self.options.automation_mode == 'NONE' or
1573 self.options.auto_run_on_start):
Peter Ammon1e1ec572014-06-26 17:56:32 -07001574 self.run_enqueue(
Ricky Liang117484a2014-04-14 11:14:41 +08001575 lambda: self.run_tests(self.test_list, untested_only=True))
Jon Salz5c344f62012-07-13 14:31:16 +08001576 self.state_instance.set_shared_data('tests_after_shutdown', None)
Ricky Liang4bff3e32014-02-20 18:46:11 +08001577 self.restore_active_run_state()
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001578
Vic Yang08505c72015-01-06 17:01:53 -08001579 system.GetBoard().OnTestStart()
1580
Dean Liao592e4d52013-01-10 20:06:39 +08001581 self.may_disable_cros_shortcut_keys()
1582
1583 def may_disable_cros_shortcut_keys(self):
1584 test_options = self.test_list.options
1585 if test_options.disable_cros_shortcut_keys:
1586 logging.info('Filter ChromeOS shortcut keys.')
1587 self.key_filter = KeyFilter(
1588 unmap_caps_lock=test_options.disable_caps_lock,
1589 caps_lock_keycode=test_options.caps_lock_keycode)
1590 self.key_filter.Start()
1591
Jon Salz0e6532d2012-10-25 16:30:11 +08001592 def _should_sync_time(self, foreground=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001593 """Returns True if we should attempt syncing time with shopfloor.
Jon Salz0e6532d2012-10-25 16:30:11 +08001594
1595 Args:
1596 foreground: If True, synchronizes even if background syncing
1597 is disabled (e.g., in explicit sync requests from the
1598 SyncShopfloor test).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001599 """
Jon Salz0e6532d2012-10-25 16:30:11 +08001600 return ((foreground or
1601 self.test_list.options.sync_time_period_secs) and
Jon Salz54882d02012-08-31 01:57:54 +08001602 self.time_sanitizer and
1603 (not self.time_synced) and
1604 (not factory.in_chroot()))
1605
Jon Salz0e6532d2012-10-25 16:30:11 +08001606 def sync_time_with_shopfloor_server(self, foreground=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001607 """Syncs time with shopfloor server, if not yet synced.
Jon Salz54882d02012-08-31 01:57:54 +08001608
Jon Salz0e6532d2012-10-25 16:30:11 +08001609 Args:
1610 foreground: If True, synchronizes even if background syncing
1611 is disabled (e.g., in explicit sync requests from the
1612 SyncShopfloor test).
1613
Jon Salz54882d02012-08-31 01:57:54 +08001614 Returns:
1615 False if no time sanitizer is available, or True if this sync (or a
1616 previous sync) succeeded.
1617
1618 Raises:
1619 Exception if unable to contact the shopfloor server.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001620 """
Jon Salz0e6532d2012-10-25 16:30:11 +08001621 if self._should_sync_time(foreground):
Jon Salz54882d02012-08-31 01:57:54 +08001622 self.time_sanitizer.SyncWithShopfloor()
1623 self.time_synced = True
1624 return self.time_synced
1625
Jon Salzb92c5112012-09-21 15:40:11 +08001626 def log_disk_space_stats(self):
Jon Salz18e0e022013-06-11 17:13:39 +08001627 if (utils.in_chroot() or
1628 not self.test_list.options.log_disk_space_period_secs):
Jon Salzb92c5112012-09-21 15:40:11 +08001629 return
1630
1631 now = time.time()
1632 if (self.last_log_disk_space_time and
1633 now - self.last_log_disk_space_time <
1634 self.test_list.options.log_disk_space_period_secs):
1635 return
1636 self.last_log_disk_space_time = now
1637
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001638 # Upload event if stateful partition usage is above threshold.
1639 # Stateful partition is mounted on /usr/local, while
1640 # encrypted stateful partition is mounted on /var.
1641 # If there are too much logs in the factory process,
1642 # these two partitions might get full.
Jon Salzb92c5112012-09-21 15:40:11 +08001643 try:
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001644 vfs_infos = disk_space.GetAllVFSInfo()
1645 stateful_info, encrypted_info = None, None
1646 for vfs_info in vfs_infos.values():
1647 if '/usr/local' in vfs_info.mount_points:
1648 stateful_info = vfs_info
1649 if '/var' in vfs_info.mount_points:
1650 encrypted_info = vfs_info
1651
1652 stateful = disk_space.GetPartitionUsage(stateful_info)
1653 encrypted = disk_space.GetPartitionUsage(encrypted_info)
1654
Ricky Liang45c73e72015-01-15 15:00:30 +08001655 above_threshold = (
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001656 self.test_list.options.stateful_usage_threshold and
1657 max(stateful.bytes_used_pct,
1658 stateful.inodes_used_pct,
1659 encrypted.bytes_used_pct,
1660 encrypted.inodes_used_pct) >
Ricky Liang45c73e72015-01-15 15:00:30 +08001661 self.test_list.options.stateful_usage_threshold)
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001662
1663 if above_threshold:
1664 self.event_log.Log('stateful_partition_usage',
Ricky Liang45c73e72015-01-15 15:00:30 +08001665 partitions={
1666 'stateful': {
1667 'bytes_used_pct': FloatDigit(stateful.bytes_used_pct, 2),
1668 'inodes_used_pct': FloatDigit(stateful.inodes_used_pct, 2)},
1669 'encrypted_stateful': {
1670 'bytes_used_pct': FloatDigit(encrypted.bytes_used_pct, 2),
1671 'inodes_used_pct': FloatDigit(encrypted.inodes_used_pct, 2)}
1672 })
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001673 self.log_watcher.ScanEventLogs()
Cheng-Yi Chiang00798e72013-06-20 18:16:39 +08001674 if (not utils.in_chroot() and
1675 self.test_list.options.stateful_usage_above_threshold_action):
1676 Spawn(self.test_list.options.stateful_usage_above_threshold_action,
1677 call=True)
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001678
1679 message = disk_space.FormatSpaceUsedAll(vfs_infos)
Jon Salz3c493bb2013-02-07 17:24:58 +08001680 if message != self.last_log_disk_space_message:
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001681 if above_threshold:
1682 logging.warning(message)
1683 else:
1684 logging.info(message)
Jon Salz3c493bb2013-02-07 17:24:58 +08001685 self.last_log_disk_space_message = message
Jon Salzb92c5112012-09-21 15:40:11 +08001686 except: # pylint: disable=W0702
1687 logging.exception('Unable to get disk space used')
1688
Justin Chuang83813982013-05-13 01:26:32 +08001689 def check_battery(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001690 """Checks the current battery status.
Justin Chuang83813982013-05-13 01:26:32 +08001691
1692 Logs current battery charging level and status to log. If the battery level
1693 is lower below warning_low_battery_pct, send warning event to shopfloor.
1694 If the battery level is lower below critical_low_battery_pct, flush disks.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001695 """
Justin Chuang83813982013-05-13 01:26:32 +08001696 if not self.test_list.options.check_battery_period_secs:
1697 return
1698
1699 now = time.time()
1700 if (self.last_check_battery_time and
1701 now - self.last_check_battery_time <
1702 self.test_list.options.check_battery_period_secs):
1703 return
1704 self.last_check_battery_time = now
1705
1706 message = ''
1707 log_level = logging.INFO
1708 try:
1709 power = system.GetBoard().power
1710 if not power.CheckBatteryPresent():
1711 message = 'Battery is not present'
1712 else:
1713 ac_present = power.CheckACPresent()
1714 charge_pct = power.GetChargePct(get_float=True)
1715 message = ('Current battery level %.1f%%, AC charger is %s' %
1716 (charge_pct, 'connected' if ac_present else 'disconnected'))
1717
1718 if charge_pct > self.test_list.options.critical_low_battery_pct:
1719 critical_low_battery = False
1720 else:
1721 critical_low_battery = True
1722 # Only sync disks when battery level is still above minimum
1723 # value. This can be used for offline analysis when shopfloor cannot
1724 # be connected.
1725 if charge_pct > MIN_BATTERY_LEVEL_FOR_DISK_SYNC:
1726 logging.warning('disk syncing for critical low battery situation')
1727 os.system('sync; sync; sync')
1728 else:
1729 logging.warning('disk syncing is cancelled '
1730 'because battery level is lower than %.1f',
1731 MIN_BATTERY_LEVEL_FOR_DISK_SYNC)
1732
1733 # Notify shopfloor server
1734 if (critical_low_battery or
1735 (not ac_present and
1736 charge_pct <= self.test_list.options.warning_low_battery_pct)):
1737 log_level = logging.WARNING
1738
1739 self.event_log.Log('low_battery',
1740 battery_level=charge_pct,
1741 charger_connected=ac_present,
1742 critical=critical_low_battery)
1743 self.log_watcher.KickWatchThread()
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001744 if self.test_list.options.enable_sync_log:
1745 self.system_log_manager.KickToSync()
Ricky Liang45c73e72015-01-15 15:00:30 +08001746 except: # pylint: disable=W0702
Justin Chuang83813982013-05-13 01:26:32 +08001747 logging.exception('Unable to check battery or notify shopfloor')
1748 finally:
1749 if message != self.last_check_battery_message:
1750 logging.log(log_level, message)
1751 self.last_check_battery_message = message
1752
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001753 def check_core_dump(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001754 """Checks if there is any core dumped file.
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001755
1756 Removes unwanted core dump files immediately.
1757 Syncs those files matching watch list to server with a delay between
1758 each sync. After the files have been synced to server, deletes the files.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001759 """
Vic Yang6cee2472014-10-22 17:18:52 -07001760 if not self.core_dump_manager:
1761 return
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001762 core_dump_files = self.core_dump_manager.ScanFiles()
1763 if core_dump_files:
1764 now = time.time()
1765 if (self.last_kick_sync_time and now - self.last_kick_sync_time <
1766 self.test_list.options.kick_sync_min_interval_secs):
1767 return
1768 self.last_kick_sync_time = now
1769
1770 # Sends event to server
1771 self.event_log.Log('core_dumped', files=core_dump_files)
1772 self.log_watcher.KickWatchThread()
1773
1774 # Syncs files to server
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001775 if self.test_list.options.enable_sync_log:
1776 self.system_log_manager.KickToSync(
Cheng-Yi Chiangd3516a32013-07-17 15:30:47 +08001777 core_dump_files, self.core_dump_manager.ClearFiles)
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001778
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001779 def check_log_rotation(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001780 """Checks log rotation file presence/absence according to test_list option.
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001781
1782 Touch /var/lib/cleanup_logs_paused if test_list.options.disable_log_rotation
1783 is True, delete it otherwise. This must be done in idle loop because
1784 autotest client will touch /var/lib/cleanup_logs_paused each time it runs
1785 an autotest.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001786 """
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001787 if utils.in_chroot():
1788 return
1789 try:
1790 if self.test_list.options.disable_log_rotation:
1791 open(CLEANUP_LOGS_PAUSED, 'w').close()
1792 else:
1793 file_utils.TryUnlink(CLEANUP_LOGS_PAUSED)
1794 except: # pylint: disable=W0702
1795 # Oh well. Logs an error (but no trace)
1796 logging.info(
1797 'Unable to %s %s: %s',
1798 'touch' if self.test_list.options.disable_log_rotation else 'delete',
1799 CLEANUP_LOGS_PAUSED, utils.FormatExceptionOnly())
1800
Jon Salz8fa8e832012-07-13 19:04:09 +08001801 def sync_time_in_background(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001802 """Writes out current time and tries to sync with shopfloor server."""
Jon Salzb22d1172012-08-06 10:38:57 +08001803 if not self.time_sanitizer:
1804 return
1805
1806 # Write out the current time.
1807 self.time_sanitizer.SaveTime()
1808
Jon Salz54882d02012-08-31 01:57:54 +08001809 if not self._should_sync_time():
Jon Salz8fa8e832012-07-13 19:04:09 +08001810 return
1811
1812 now = time.time()
1813 if self.last_sync_time and (
1814 now - self.last_sync_time <
1815 self.test_list.options.sync_time_period_secs):
1816 # Not yet time for another check.
1817 return
1818 self.last_sync_time = now
1819
1820 def target():
1821 try:
Jon Salz54882d02012-08-31 01:57:54 +08001822 self.sync_time_with_shopfloor_server()
Jon Salz8fa8e832012-07-13 19:04:09 +08001823 except: # pylint: disable=W0702
1824 # Oh well. Log an error (but no trace)
1825 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +08001826 'Unable to get time from shopfloor server: %s',
1827 utils.FormatExceptionOnly())
Jon Salz8fa8e832012-07-13 19:04:09 +08001828
1829 thread = threading.Thread(target=target)
1830 thread.daemon = True
1831 thread.start()
1832
Peter Ammon1e1ec572014-06-26 17:56:32 -07001833 def perform_periodic_tasks(self):
1834 """Override of base method to perform periodic work.
Vic Yang4953fc12012-07-26 16:19:53 +08001835
Peter Ammon1e1ec572014-06-26 17:56:32 -07001836 This method must not raise exceptions.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001837 """
Peter Ammon1e1ec572014-06-26 17:56:32 -07001838 super(Goofy, self).perform_periodic_tasks()
Jon Salzb22d1172012-08-06 10:38:57 +08001839
Vic Yang311ddb82012-09-26 12:08:28 +08001840 self.check_exclusive()
cychiang21886742012-07-05 15:16:32 +08001841 self.check_for_updates()
Jon Salz8fa8e832012-07-13 19:04:09 +08001842 self.sync_time_in_background()
Jon Salzb92c5112012-09-21 15:40:11 +08001843 self.log_disk_space_stats()
Justin Chuang83813982013-05-13 01:26:32 +08001844 self.check_battery()
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001845 self.check_core_dump()
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001846 self.check_log_rotation()
Jon Salz57717ca2012-04-04 16:47:25 +08001847
Jon Salzd15bbcf2013-05-21 17:33:57 +08001848 def handle_event_logs(self, chunks):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001849 """Callback for event watcher.
Jon Salz258a40c2012-04-19 12:34:01 +08001850
Jon Salz0697cbf2012-07-04 15:14:04 +08001851 Attempts to upload the event logs to the shopfloor server.
Vic Yang93027612013-05-06 02:42:49 +08001852
1853 Args:
Jon Salzd15bbcf2013-05-21 17:33:57 +08001854 chunks: A list of Chunk objects.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001855 """
Vic Yang93027612013-05-06 02:42:49 +08001856 first_exception = None
1857 exception_count = 0
1858
Jon Salzd15bbcf2013-05-21 17:33:57 +08001859 for chunk in chunks:
Vic Yang93027612013-05-06 02:42:49 +08001860 try:
Jon Salzcddb6402013-05-23 12:56:42 +08001861 description = 'event logs (%s)' % str(chunk)
Vic Yang93027612013-05-06 02:42:49 +08001862 start_time = time.time()
1863 shopfloor_client = shopfloor.get_instance(
Ricky Liang45c73e72015-01-15 15:00:30 +08001864 detect=True,
1865 timeout=self.test_list.options.shopfloor_timeout_secs)
1866 shopfloor_client.UploadEvent(chunk.log_name + '.' +
Jon Salzd15bbcf2013-05-21 17:33:57 +08001867 event_log.GetReimageId(),
1868 Binary(chunk.chunk))
Vic Yang93027612013-05-06 02:42:49 +08001869 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +08001870 'Successfully synced %s in %.03f s',
1871 description, time.time() - start_time)
1872 except: # pylint: disable=W0702
Jon Salzd15bbcf2013-05-21 17:33:57 +08001873 first_exception = (first_exception or (chunk.log_name + ': ' +
Vic Yang93027612013-05-06 02:42:49 +08001874 utils.FormatExceptionOnly()))
1875 exception_count += 1
1876
1877 if exception_count:
1878 if exception_count == 1:
1879 msg = 'Log upload failed: %s' % first_exception
1880 else:
1881 msg = '%d log upload failed; first is: %s' % (
1882 exception_count, first_exception)
1883 raise Exception(msg)
1884
Ricky Liang45c73e72015-01-15 15:00:30 +08001885 def run_tests_with_status(self, statuses_to_run, starting_at=None, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001886 """Runs all top-level tests with a particular status.
Jon Salz0405ab52012-03-16 15:26:52 +08001887
Jon Salz0697cbf2012-07-04 15:14:04 +08001888 All active tests, plus any tests to re-run, are reset.
Jon Salz57717ca2012-04-04 16:47:25 +08001889
Jon Salz0697cbf2012-07-04 15:14:04 +08001890 Args:
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001891 statuses_to_run: The particular status that caller wants to run.
Jon Salz0697cbf2012-07-04 15:14:04 +08001892 starting_at: If provided, only auto-runs tests beginning with
1893 this test.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001894 root: The root of tests to run. If not provided, it will be
1895 the root of all tests.
1896 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001897 root = root or self.test_list
Jon Salz57717ca2012-04-04 16:47:25 +08001898
Jon Salz0697cbf2012-07-04 15:14:04 +08001899 if starting_at:
1900 # Make sure they passed a test, not a string.
1901 assert isinstance(starting_at, factory.FactoryTest)
Jon Salz0405ab52012-03-16 15:26:52 +08001902
Jon Salz0697cbf2012-07-04 15:14:04 +08001903 tests_to_reset = []
1904 tests_to_run = []
Jon Salz0405ab52012-03-16 15:26:52 +08001905
Jon Salz0697cbf2012-07-04 15:14:04 +08001906 found_starting_at = False
Jon Salz0405ab52012-03-16 15:26:52 +08001907
Jon Salz0697cbf2012-07-04 15:14:04 +08001908 for test in root.get_top_level_tests():
1909 if starting_at:
1910 if test == starting_at:
1911 # We've found starting_at; do auto-run on all
1912 # subsequent tests.
1913 found_starting_at = True
1914 if not found_starting_at:
1915 # Don't start this guy yet
1916 continue
Jon Salz0405ab52012-03-16 15:26:52 +08001917
Jon Salz0697cbf2012-07-04 15:14:04 +08001918 status = test.get_state().status
1919 if status == TestState.ACTIVE or status in statuses_to_run:
1920 # Reset the test (later; we will need to abort
1921 # all active tests first).
1922 tests_to_reset.append(test)
1923 if status in statuses_to_run:
1924 tests_to_run.append(test)
Jon Salz0405ab52012-03-16 15:26:52 +08001925
Jon Salz6dc031d2013-06-19 13:06:23 +08001926 self.abort_active_tests('Operator requested run/re-run of certain tests')
Jon Salz258a40c2012-04-19 12:34:01 +08001927
Jon Salz0697cbf2012-07-04 15:14:04 +08001928 # Reset all statuses of the tests to run (in case any tests were active;
1929 # we want them to be run again).
1930 for test_to_reset in tests_to_reset:
1931 for test in test_to_reset.walk():
1932 test.update_state(status=TestState.UNTESTED)
Jon Salz57717ca2012-04-04 16:47:25 +08001933
Jon Salz0697cbf2012-07-04 15:14:04 +08001934 self.run_tests(tests_to_run, untested_only=True)
Jon Salz0405ab52012-03-16 15:26:52 +08001935
Jon Salz0697cbf2012-07-04 15:14:04 +08001936 def restart_tests(self, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001937 """Restarts all tests."""
Jon Salz0697cbf2012-07-04 15:14:04 +08001938 root = root or self.test_list
Jon Salz0405ab52012-03-16 15:26:52 +08001939
Jon Salz6dc031d2013-06-19 13:06:23 +08001940 self.abort_active_tests('Operator requested restart of certain tests')
Jon Salz0697cbf2012-07-04 15:14:04 +08001941 for test in root.walk():
Ricky Liangfea4ac92014-08-21 11:55:59 +08001942 test.update_state(status=TestState.UNTESTED)
Jon Salz0697cbf2012-07-04 15:14:04 +08001943 self.run_tests(root)
Hung-Te Lin96632362012-03-20 21:14:18 +08001944
Jon Salz0697cbf2012-07-04 15:14:04 +08001945 def auto_run(self, starting_at=None, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001946 """"Auto-runs" tests that have not been run yet.
Hung-Te Lin96632362012-03-20 21:14:18 +08001947
Jon Salz0697cbf2012-07-04 15:14:04 +08001948 Args:
1949 starting_at: If provide, only auto-runs tests beginning with
1950 this test.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001951 root: If provided, the root of tests to run. If not provided, the root
1952 will be test_list (root of all tests).
1953 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001954 root = root or self.test_list
1955 self.run_tests_with_status([TestState.UNTESTED, TestState.ACTIVE],
Ricky Liang45c73e72015-01-15 15:00:30 +08001956 starting_at=starting_at,
1957 root=root)
Jon Salz968e90b2012-03-18 16:12:43 +08001958
Jon Salz0697cbf2012-07-04 15:14:04 +08001959 def re_run_failed(self, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001960 """Re-runs failed tests."""
Jon Salz0697cbf2012-07-04 15:14:04 +08001961 root = root or self.test_list
1962 self.run_tests_with_status([TestState.FAILED], root=root)
Jon Salz57717ca2012-04-04 16:47:25 +08001963
Jon Salz0697cbf2012-07-04 15:14:04 +08001964 def show_review_information(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001965 """Event handler for showing review information screen.
Jon Salz57717ca2012-04-04 16:47:25 +08001966
Peter Ammon1e1ec572014-06-26 17:56:32 -07001967 The information screen is rendered by main UI program (ui.py), so in
Jon Salz0697cbf2012-07-04 15:14:04 +08001968 goofy we only need to kill all active tests, set them as untested, and
1969 clear remaining tests.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001970 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001971 self.kill_active_tests(False)
Jon Salza6711d72012-07-18 14:33:03 +08001972 self.cancel_pending_tests()
Jon Salz57717ca2012-04-04 16:47:25 +08001973
Jon Salz0697cbf2012-07-04 15:14:04 +08001974 def handle_switch_test(self, event):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001975 """Switches to a particular test.
Jon Salz0405ab52012-03-16 15:26:52 +08001976
Ricky Liang6fe218c2013-12-27 15:17:17 +08001977 Args:
1978 event: The SWITCH_TEST event.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001979 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001980 test = self.test_list.lookup_path(event.path)
1981 if not test:
1982 logging.error('Unknown test %r', event.key)
1983 return
Jon Salz73e0fd02012-04-04 11:46:38 +08001984
Jon Salz0697cbf2012-07-04 15:14:04 +08001985 invoc = self.invocations.get(test)
1986 if invoc and test.backgroundable:
1987 # Already running: just bring to the front if it
1988 # has a UI.
1989 logging.info('Setting visible test to %s', test.path)
Jon Salz36fbbb52012-07-05 13:45:06 +08001990 self.set_visible_test(test)
Jon Salz0697cbf2012-07-04 15:14:04 +08001991 return
Jon Salz73e0fd02012-04-04 11:46:38 +08001992
Jon Salz6dc031d2013-06-19 13:06:23 +08001993 self.abort_active_tests('Operator requested abort (switch_test)')
Jon Salz0697cbf2012-07-04 15:14:04 +08001994 for t in test.walk():
1995 t.update_state(status=TestState.UNTESTED)
Jon Salz73e0fd02012-04-04 11:46:38 +08001996
Jon Salz0697cbf2012-07-04 15:14:04 +08001997 if self.test_list.options.auto_run_on_keypress:
1998 self.auto_run(starting_at=test)
1999 else:
2000 self.run_tests(test)
Jon Salz73e0fd02012-04-04 11:46:38 +08002001
Wei-Ning Huang38b75f02015-02-25 18:25:14 +08002002 def handle_key_filter_mode(self, event):
2003 if self.key_filter:
2004 if getattr(event, 'enabled'):
2005 self.key_filter.Start()
2006 else:
2007 self.key_filter.Stop()
2008
Jon Salz0697cbf2012-07-04 15:14:04 +08002009 def wait(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002010 """Waits for all pending invocations.
Jon Salz0697cbf2012-07-04 15:14:04 +08002011
2012 Useful for testing.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002013 """
Jon Salz1acc8742012-07-17 17:45:55 +08002014 while self.invocations:
2015 for k, v in self.invocations.iteritems():
2016 logging.info('Waiting for %s to complete...', k)
2017 v.thread.join()
2018 self.reap_completed_tests()
Jon Salz0697cbf2012-07-04 15:14:04 +08002019
Hung-Te Linf2f78f72012-02-08 19:27:11 +08002020if __name__ == '__main__':
Peter Ammona3d298c2014-09-23 10:11:02 -07002021 Goofy.run_main_and_exit()