blob: e13fa0b089517120c7c7165fc5f88019795b2641 [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 Linb6287242016-05-18 14:39:05 +080028from cros.factory.device import device_utils
29from cros.factory.device import DeviceException
Hung-Te Lincc41d2a2014-10-29 13:35:20 +080030from cros.factory.goofy import connection_manager
Vic Yangd80ea752014-09-24 16:07:14 +080031from cros.factory.goofy import test_environment
32from cros.factory.goofy import time_sanitizer
33from cros.factory.goofy import updater
34from cros.factory.goofy.goofy_base import GoofyBase
35from cros.factory.goofy.goofy_rpc import GoofyRPC
36from cros.factory.goofy.invocation import TestArgEnv
37from cros.factory.goofy.invocation import TestInvocation
38from cros.factory.goofy.link_manager import PresenterLinkManager
Vic Yange2c76a82014-10-30 12:48:19 -070039from cros.factory.goofy import prespawner
Vic Yangd80ea752014-09-24 16:07:14 +080040from cros.factory.goofy.system_log_manager import SystemLogManager
Wei-Ning Huang38b75f02015-02-25 18:25:14 +080041from cros.factory.goofy.terminal_manager import TerminalManager
Vic Yangd80ea752014-09-24 16:07:14 +080042from cros.factory.goofy.web_socket_manager import WebSocketManager
jcliangcd688182012-08-20 21:01:26 +080043from cros.factory.test import factory
Jon Salz51528e12012-07-02 18:54:45 +080044from cros.factory.test import shopfloor
Hung-Te Lin6a72c642015-12-13 22:09:09 +080045from cros.factory.test import state
Hung-Te Linb6287242016-05-18 14:39:05 +080046from cros.factory.test import testlog
47from cros.factory.test import testlog_goofy
48from cros.factory.test.e2e_test.common import AutomationMode
49from cros.factory.test.e2e_test.common import AutomationModePrompt
50from cros.factory.test.e2e_test.common import ParseAutomationMode
51from cros.factory.test.env import paths
Jon Salz83591782012-06-26 11:09:58 +080052from cros.factory.test.event import Event
53from cros.factory.test.event import EventClient
54from cros.factory.test.event import EventServer
Hung-Te Linb6287242016-05-18 14:39:05 +080055from cros.factory.test import event_log
56from cros.factory.test.event_log import EventLog
57from cros.factory.test.event_log import FloatDigit
58from cros.factory.test.event_log import GetBootSequence
Hung-Te Lin91492a12014-11-25 18:56:30 +080059from cros.factory.test.event_log_watcher import EventLogWatcher
jcliangcd688182012-08-20 21:01:26 +080060from cros.factory.test.factory import TestState
Hung-Te Lin3f096842016-01-13 17:37:06 +080061from cros.factory.test.rules import phase
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +080062from cros.factory.test.test_lists import test_lists
Hung-Te Linc367ac02015-12-22 19:33:23 +080063from cros.factory.test.utils.charge_manager import ChargeManager
64from cros.factory.test.utils.core_dump_manager import CoreDumpManager
65from cros.factory.test.utils.cpufreq_manager import CpufreqManager
Hung-Te Lind3ee0102015-12-28 17:21:50 +080066from cros.factory.tools import disk_space
Hung-Te Linb6287242016-05-18 14:39:05 +080067from cros.factory.tools.key_filter import KeyFilter
Hung-Te Linf707b242016-01-08 23:11:42 +080068from cros.factory.utils import debug_utils
Jon Salz2af235d2013-06-24 14:47:21 +080069from cros.factory.utils import file_utils
Joel Kitchingb85ed7f2014-10-08 18:24:39 +080070from cros.factory.utils import net_utils
Hung-Te Lin4e6357c2016-01-08 14:32:00 +080071from cros.factory.utils import process_utils
72from cros.factory.utils import sys_utils
73from cros.factory.utils import time_utils
Hung-Te Linf707b242016-01-08 23:11:42 +080074from cros.factory.utils import type_utils
Hung-Te Linf2f78f72012-02-08 19:27:11 +080075
76
Hung-Te Linf2f78f72012-02-08 19:27:11 +080077HWID_CFG_PATH = '/usr/local/share/chromeos-hwid/cfg'
Joel Kitching625ff0f2016-05-16 14:59:40 -070078CACHES_DIR = os.path.join(paths.GetStateRoot(), 'caches')
Hung-Te Linf2f78f72012-02-08 19:27:11 +080079
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +080080CLEANUP_LOGS_PAUSED = '/var/lib/cleanup_logs_paused'
81
Jon Salz5c344f62012-07-13 14:31:16 +080082# Value for tests_after_shutdown that forces auto-run (e.g., after
83# a factory update, when the available set of tests might change).
84FORCE_AUTO_RUN = 'force_auto_run'
85
Justin Chuang83813982013-05-13 01:26:32 +080086# Sync disks when battery level is higher than this value.
87# Otherwise, power loss during disk sync operation may incur even worse outcome.
88MIN_BATTERY_LEVEL_FOR_DISK_SYNC = 1.0
89
Ricky Liang45c73e72015-01-15 15:00:30 +080090MAX_CRASH_FILE_SIZE = 64 * 1024
Jon Salze12c2b32013-06-25 16:24:34 +080091
Hung-Te Linf707b242016-01-08 23:11:42 +080092Status = type_utils.Enum(['UNINITIALIZED', 'INITIALIZING', 'RUNNING',
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +080093 'TERMINATING', 'TERMINATED'])
Jon Salzd7550792013-07-12 05:49:27 +080094
Ricky Liang45c73e72015-01-15 15:00:30 +080095
Hung-Te Linf2f78f72012-02-08 19:27:11 +080096def get_hwid_cfg():
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +080097 """Returns the HWID config tag, or an empty string if none can be found."""
Jon Salz0697cbf2012-07-04 15:14:04 +080098 if 'CROS_HWID' in os.environ:
99 return os.environ['CROS_HWID']
100 if os.path.exists(HWID_CFG_PATH):
Ricky Liang45c73e72015-01-15 15:00:30 +0800101 with open(HWID_CFG_PATH, 'r') as hwid_cfg_handle:
Jon Salz0697cbf2012-07-04 15:14:04 +0800102 return hwid_cfg_handle.read().strip()
103 return ''
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800104
105
Jon Salz73e0fd02012-04-04 11:46:38 +0800106_inited_logging = False
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800107
Ricky Liang45c73e72015-01-15 15:00:30 +0800108
Peter Ammon1e1ec572014-06-26 17:56:32 -0700109class Goofy(GoofyBase):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800110 """The main factory flow.
Jon Salz0697cbf2012-07-04 15:14:04 +0800111
112 Note that all methods in this class must be invoked from the main
113 (event) thread. Other threads, such as callbacks and TestInvocation
114 methods, should instead post events on the run queue.
115
116 TODO: Unit tests. (chrome-os-partner:7409)
117
118 Properties:
119 uuid: A unique UUID for this invocation of Goofy.
120 state_instance: An instance of FactoryState.
121 state_server: The FactoryState XML/RPC server.
122 state_server_thread: A thread running state_server.
123 event_server: The EventServer socket server.
124 event_server_thread: A thread running event_server.
125 event_client: A client to the event server.
126 connection_manager: The connection_manager object.
Cheng-Yi Chiang835f2682013-05-06 22:15:48 +0800127 system_log_manager: The SystemLogManager object.
128 core_dump_manager: The CoreDumpManager object.
Jon Salz0697cbf2012-07-04 15:14:04 +0800129 ui_process: The factory ui process object.
Jon Salz0697cbf2012-07-04 15:14:04 +0800130 invocations: A map from FactoryTest objects to the corresponding
131 TestInvocations objects representing active tests.
132 tests_to_run: A deque of tests that should be run when the current
133 test(s) complete.
134 options: Command-line options.
135 args: Command-line args.
136 test_list: The test list.
Jon Salz128b0932013-07-03 16:55:26 +0800137 test_lists: All new-style test lists.
Ricky Liang4bff3e32014-02-20 18:46:11 +0800138 run_id: The identifier for latest test run.
139 scheduled_run_tests: The list of tests scheduled for latest test run.
Jon Salz0697cbf2012-07-04 15:14:04 +0800140 event_handlers: Map of Event.Type to the method used to handle that
141 event. If the method has an 'event' argument, the event is passed
142 to the handler.
Jon Salz3c493bb2013-02-07 17:24:58 +0800143 last_log_disk_space_message: The last message we logged about disk space
144 (to avoid duplication).
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +0800145 last_kick_sync_time: The last time to kick system_log_manager to sync
146 because of core dump files (to avoid kicking too soon then abort the
147 sync.)
Jon Salz416f9cc2013-05-10 18:32:50 +0800148 hooks: A Hooks object containing hooks for various Goofy actions.
Jon Salzd7550792013-07-12 05:49:27 +0800149 status: The current Goofy status (a member of the Status enum).
Peter Ammon948b7172014-07-15 12:43:06 -0700150 link_manager: Instance of PresenterLinkManager for communicating
151 with GoofyPresenter
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800152 """
Ricky Liang45c73e72015-01-15 15:00:30 +0800153
Jon Salz0697cbf2012-07-04 15:14:04 +0800154 def __init__(self):
Peter Ammon1e1ec572014-06-26 17:56:32 -0700155 super(Goofy, self).__init__()
Jon Salz0697cbf2012-07-04 15:14:04 +0800156 self.uuid = str(uuid.uuid4())
157 self.state_instance = None
158 self.state_server = None
159 self.state_server_thread = None
Jon Salz16d10542012-07-23 12:18:45 +0800160 self.goofy_rpc = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800161 self.event_server = None
162 self.event_server_thread = None
163 self.event_client = None
164 self.connection_manager = None
Vic Yang4953fc12012-07-26 16:19:53 +0800165 self.charge_manager = None
Dean Liao88b93192014-10-23 19:37:41 +0800166 self._can_charge = True
Jon Salz8fa8e832012-07-13 19:04:09 +0800167 self.time_sanitizer = None
168 self.time_synced = False
Jon Salz0697cbf2012-07-04 15:14:04 +0800169 self.log_watcher = None
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800170 self.system_log_manager = None
Cheng-Yi Chiang835f2682013-05-06 22:15:48 +0800171 self.core_dump_manager = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800172 self.event_log = None
Chun-Ta Lin53cbbd52016-06-08 21:42:19 +0800173 self.testlog = None
Vic Yange2c76a82014-10-30 12:48:19 -0700174 self.autotest_prespawner = None
175 self.pytest_prespawner = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800176 self.ui_process = None
Vic Yanga3cecf82014-12-26 00:44:21 -0800177 self._ui_initialized = False
Jon Salzc79a9982012-08-30 04:42:01 +0800178 self.dummy_shopfloor = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800179 self.invocations = {}
180 self.tests_to_run = deque()
181 self.visible_test = None
182 self.chrome = None
Jon Salz416f9cc2013-05-10 18:32:50 +0800183 self.hooks = None
Vic Yangd8990da2013-06-27 16:57:43 +0800184 self.cpu_usage_watcher = None
Hung-Te Lin23cb7612016-01-19 19:19:32 +0800185 self.thermal_watcher = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800186
187 self.options = None
188 self.args = None
189 self.test_list = None
Jon Salz128b0932013-07-03 16:55:26 +0800190 self.test_lists = None
Ricky Liang4bff3e32014-02-20 18:46:11 +0800191 self.run_id = None
192 self.scheduled_run_tests = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800193 self.env = None
Jon Salzb22d1172012-08-06 10:38:57 +0800194 self.last_idle = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800195 self.last_shutdown_time = None
cychiang21886742012-07-05 15:16:32 +0800196 self.last_update_check = None
Cheng-Yi Chiang194d3c02015-03-16 14:37:15 +0800197 self._suppress_periodic_update_messages = False
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +0800198 self._suppress_event_log_error_messages = False
Jon Salz8fa8e832012-07-13 19:04:09 +0800199 self.last_sync_time = None
Jon Salzb92c5112012-09-21 15:40:11 +0800200 self.last_log_disk_space_time = None
Jon Salz3c493bb2013-02-07 17:24:58 +0800201 self.last_log_disk_space_message = None
Justin Chuang83813982013-05-13 01:26:32 +0800202 self.last_check_battery_time = None
203 self.last_check_battery_message = None
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +0800204 self.last_kick_sync_time = None
Vic Yang311ddb82012-09-26 12:08:28 +0800205 self.exclusive_items = set()
Dean Liao592e4d52013-01-10 20:06:39 +0800206 self.key_filter = None
Jon Salzce6a7f82013-06-10 18:22:54 +0800207 self.cpufreq_manager = None
Jon Salzd7550792013-07-12 05:49:27 +0800208 self.status = Status.UNINITIALIZED
Ricky Liang36512a32014-07-25 11:47:04 +0800209 self.ready_for_ui_connection = False
Peter Ammon1e1ec572014-06-26 17:56:32 -0700210 self.link_manager = None
Hung-Te Linef7f2be2015-07-20 20:38:51 +0800211 self.is_restart_requested = False
Jon Salz0697cbf2012-07-04 15:14:04 +0800212
Hung-Te Lin6a72c642015-12-13 22:09:09 +0800213 # TODO(hungte) Support controlling remote DUT.
Hung-Te Linb6287242016-05-18 14:39:05 +0800214 self.dut = device_utils.CreateDUTInterface()
Hung-Te Lin6a72c642015-12-13 22:09:09 +0800215
Jon Salz85a39882012-07-05 16:45:04 +0800216 def test_or_root(event, parent_or_group=True):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800217 """Returns the test affected by a particular event.
Jon Salz85a39882012-07-05 16:45:04 +0800218
219 Args:
220 event: The event containing an optional 'path' attribute.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800221 parent_or_group: If True, returns the top-level parent for a test (the
Jon Salz85a39882012-07-05 16:45:04 +0800222 root node of the tests that need to be run together if the given test
223 path is to be run).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800224 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800225 try:
226 path = event.path
227 except AttributeError:
228 path = None
229
230 if path:
Jon Salz85a39882012-07-05 16:45:04 +0800231 test = self.test_list.lookup_path(path)
232 if parent_or_group:
233 test = test.get_top_level_parent_or_group()
234 return test
Jon Salz0697cbf2012-07-04 15:14:04 +0800235 else:
236 return self.test_list
237
238 self.event_handlers = {
Ricky Liang45c73e72015-01-15 15:00:30 +0800239 Event.Type.SWITCH_TEST: self.handle_switch_test,
Ricky Liang45c73e72015-01-15 15:00:30 +0800240 Event.Type.RESTART_TESTS:
241 lambda event: self.restart_tests(root=test_or_root(event)),
242 Event.Type.AUTO_RUN:
243 lambda event: self.auto_run(root=test_or_root(event)),
Ricky Liang45c73e72015-01-15 15:00:30 +0800244 Event.Type.RUN_TESTS_WITH_STATUS:
245 lambda event: self.run_tests_with_status(
246 event.status,
247 root=test_or_root(event)),
Ricky Liang45c73e72015-01-15 15:00:30 +0800248 Event.Type.UPDATE_SYSTEM_INFO:
249 lambda event: self.update_system_info(),
250 Event.Type.STOP:
251 lambda event: self.stop(root=test_or_root(event, False),
252 fail=getattr(event, 'fail', False),
253 reason=getattr(event, 'reason', None)),
254 Event.Type.SET_VISIBLE_TEST:
255 lambda event: self.set_visible_test(
256 self.test_list.lookup_path(event.path)),
257 Event.Type.CLEAR_STATE:
258 lambda event: self.clear_state(
259 self.test_list.lookup_path(event.path)),
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800260 Event.Type.KEY_FILTER_MODE: self.handle_key_filter_mode,
Jon Salz0697cbf2012-07-04 15:14:04 +0800261 }
262
Jon Salz0697cbf2012-07-04 15:14:04 +0800263 self.web_socket_manager = None
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800264 self.terminal_manager = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800265
266 def destroy(self):
Ricky Liang74237a02014-09-18 15:11:23 +0800267 """Performs any shutdown tasks. Overrides base class method."""
Jon Salzd7550792013-07-12 05:49:27 +0800268 self.status = Status.TERMINATING
Jon Salz0697cbf2012-07-04 15:14:04 +0800269 if self.chrome:
270 self.chrome.kill()
271 self.chrome = None
Jon Salzc79a9982012-08-30 04:42:01 +0800272 if self.dummy_shopfloor:
273 self.dummy_shopfloor.kill()
274 self.dummy_shopfloor = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800275 if self.ui_process:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800276 process_utils.KillProcessTree(self.ui_process, 'ui')
Jon Salz0697cbf2012-07-04 15:14:04 +0800277 self.ui_process = None
278 if self.web_socket_manager:
279 logging.info('Stopping web sockets')
280 self.web_socket_manager.close()
281 self.web_socket_manager = None
282 if self.state_server_thread:
283 logging.info('Stopping state server')
284 self.state_server.shutdown()
285 self.state_server_thread.join()
286 self.state_server.server_close()
287 self.state_server_thread = None
288 if self.state_instance:
289 self.state_instance.close()
290 if self.event_server_thread:
291 logging.info('Stopping event server')
292 self.event_server.shutdown() # pylint: disable=E1101
293 self.event_server_thread.join()
294 self.event_server.server_close()
295 self.event_server_thread = None
296 if self.log_watcher:
297 if self.log_watcher.IsThreadStarted():
298 self.log_watcher.StopWatchThread()
299 self.log_watcher = None
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800300 if self.system_log_manager:
301 if self.system_log_manager.IsThreadRunning():
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +0800302 self.system_log_manager.Stop()
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800303 self.system_log_manager = None
Vic Yange2c76a82014-10-30 12:48:19 -0700304 if self.autotest_prespawner:
305 logging.info('Stopping autotest prespawner')
306 self.autotest_prespawner.stop()
307 self.autotest_prespawner = None
308 if self.pytest_prespawner:
309 logging.info('Stopping pytest prespawner')
310 self.pytest_prespawner.stop()
311 self.pytest_prespawner = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800312 if self.event_client:
313 logging.info('Closing event client')
314 self.event_client.close()
315 self.event_client = None
Jon Salzddf0d052013-06-18 12:52:44 +0800316 if self.cpufreq_manager:
317 self.cpufreq_manager.Stop()
Jon Salz0697cbf2012-07-04 15:14:04 +0800318 if self.event_log:
319 self.event_log.Close()
320 self.event_log = None
Chun-Ta Lin53cbbd52016-06-08 21:42:19 +0800321 if self.testlog:
322 self.testlog.Close()
323 self.testlog = None
Dean Liao592e4d52013-01-10 20:06:39 +0800324 if self.key_filter:
325 self.key_filter.Stop()
Vic Yangd8990da2013-06-27 16:57:43 +0800326 if self.cpu_usage_watcher:
327 self.cpu_usage_watcher.terminate()
Hung-Te Lin23cb7612016-01-19 19:19:32 +0800328 if self.thermal_watcher:
329 self.thermal_watcher.terminate()
Peter Ammon1e1ec572014-06-26 17:56:32 -0700330 if self.link_manager:
331 self.link_manager.Stop()
332 self.link_manager = None
Dean Liao592e4d52013-01-10 20:06:39 +0800333
Peter Ammon1e1ec572014-06-26 17:56:32 -0700334 super(Goofy, self).destroy()
Jon Salz0697cbf2012-07-04 15:14:04 +0800335 logging.info('Done destroying Goofy')
Jon Salzd7550792013-07-12 05:49:27 +0800336 self.status = Status.TERMINATED
Jon Salz0697cbf2012-07-04 15:14:04 +0800337
338 def start_state_server(self):
Jon Salz2af235d2013-06-24 14:47:21 +0800339 # Before starting state server, remount stateful partitions with
340 # no commit flag. The default commit time (commit=600) makes corruption
341 # too likely.
Hung-Te Lin1968d9c2016-01-08 22:55:46 +0800342 sys_utils.ResetCommitTime()
Jon Salz2af235d2013-06-24 14:47:21 +0800343
Jon Salz0697cbf2012-07-04 15:14:04 +0800344 self.state_instance, self.state_server = (
Ricky Liang45c73e72015-01-15 15:00:30 +0800345 state.create_server(bind_address='0.0.0.0'))
Jon Salz16d10542012-07-23 12:18:45 +0800346 self.goofy_rpc = GoofyRPC(self)
347 self.goofy_rpc.RegisterMethods(self.state_instance)
Jon Salz0697cbf2012-07-04 15:14:04 +0800348 logging.info('Starting state server')
349 self.state_server_thread = threading.Thread(
Ricky Liang45c73e72015-01-15 15:00:30 +0800350 target=self.state_server.serve_forever,
351 name='StateServer')
Jon Salz0697cbf2012-07-04 15:14:04 +0800352 self.state_server_thread.start()
353
354 def start_event_server(self):
355 self.event_server = EventServer()
356 logging.info('Starting factory event server')
357 self.event_server_thread = threading.Thread(
Ricky Liang45c73e72015-01-15 15:00:30 +0800358 target=self.event_server.serve_forever,
359 name='EventServer') # pylint: disable=E1101
Jon Salz0697cbf2012-07-04 15:14:04 +0800360 self.event_server_thread.start()
361
362 self.event_client = EventClient(
Ricky Liang45c73e72015-01-15 15:00:30 +0800363 callback=self.handle_event, event_loop=self.run_queue)
Jon Salz0697cbf2012-07-04 15:14:04 +0800364
365 self.web_socket_manager = WebSocketManager(self.uuid)
Ricky Liang45c73e72015-01-15 15:00:30 +0800366 self.state_server.add_handler('/event',
367 self.web_socket_manager.handle_web_socket)
Jon Salz0697cbf2012-07-04 15:14:04 +0800368
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800369 def start_terminal_server(self):
370 self.terminal_manager = TerminalManager()
371 self.state_server.add_handler('/pty',
372 self.terminal_manager.handle_web_socket)
373
Jon Salz0697cbf2012-07-04 15:14:04 +0800374 def start_ui(self):
375 ui_proc_args = [
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +0800376 os.path.join(paths.FACTORY_PACKAGE_PATH, 'test', 'ui.py'),
Ricky Liang45c73e72015-01-15 15:00:30 +0800377 self.options.test_list
378 ]
Jon Salz0697cbf2012-07-04 15:14:04 +0800379 if self.options.verbose:
380 ui_proc_args.append('-v')
381 logging.info('Starting ui %s', ui_proc_args)
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800382 self.ui_process = process_utils.Spawn(ui_proc_args)
Jon Salz0697cbf2012-07-04 15:14:04 +0800383 logging.info('Waiting for UI to come up...')
384 self.event_client.wait(
Ricky Liang45c73e72015-01-15 15:00:30 +0800385 lambda event: event.type == Event.Type.UI_READY)
Jon Salz0697cbf2012-07-04 15:14:04 +0800386 logging.info('UI has started')
387
388 def set_visible_test(self, test):
389 if self.visible_test == test:
390 return
Jon Salz2f2d42c2012-07-30 12:30:34 +0800391 if test and not test.has_ui:
392 return
Jon Salz0697cbf2012-07-04 15:14:04 +0800393
394 if test:
395 test.update_state(visible=True)
396 if self.visible_test:
397 self.visible_test.update_state(visible=False)
398 self.visible_test = test
399
Ricky Liang48e47f92014-02-26 19:31:51 +0800400 def log_startup_messages(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800401 """Logs the tail of var/log/messages and mosys and EC console logs."""
Jon Salzd4306c82012-11-30 15:16:36 +0800402 # TODO(jsalz): This is mostly a copy-and-paste of code in init_states,
403 # for factory-3004.B only. Consolidate and merge back to ToT.
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800404 if sys_utils.InChroot():
Jon Salzd4306c82012-11-30 15:16:36 +0800405 return
406
407 try:
Hung-Te Lin1a4e30c2016-01-08 23:25:10 +0800408 var_log_messages = sys_utils.GetVarLogMessagesBeforeReboot()
Jon Salzd4306c82012-11-30 15:16:36 +0800409 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +0800410 'Tail of /var/log/messages before last reboot:\n'
411 '%s', ('\n'.join(
412 ' ' + x for x in var_log_messages)))
Jon Salzd4306c82012-11-30 15:16:36 +0800413 except: # pylint: disable=W0702
414 logging.exception('Unable to grok /var/log/messages')
415
416 try:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800417 mosys_log = process_utils.Spawn(
Jon Salzd4306c82012-11-30 15:16:36 +0800418 ['mosys', 'eventlog', 'list'],
419 read_stdout=True, log_stderr_on_error=True).stdout_data
420 logging.info('System eventlog from mosys:\n%s\n', mosys_log)
421 except: # pylint: disable=W0702
422 logging.exception('Unable to read mosys eventlog')
423
Dean Liao88b93192014-10-23 19:37:41 +0800424 self.log_ec_console()
425 self.log_ec_panic_info()
426
427 @staticmethod
428 def log_ec_console():
429 """Logs EC console log into logging.info.
430
431 It logs an error message in logging.exception if an exception is raised
432 when getting EC console log.
433 For unsupported device, it logs unsupport message in logging.info
434
435 Returns:
436 EC console log string.
437 """
Jon Salzd4306c82012-11-30 15:16:36 +0800438 try:
Hung-Te Linb6287242016-05-18 14:39:05 +0800439 ec_console_log = device_utils.CreateDUTInterface().ec.GetECConsoleLog()
Jon Salzd4306c82012-11-30 15:16:36 +0800440 logging.info('EC console log after reboot:\n%s\n', ec_console_log)
Dean Liao88b93192014-10-23 19:37:41 +0800441 return ec_console_log
442 except NotImplementedError:
443 logging.info('EC console log not supported')
Jon Salzd4306c82012-11-30 15:16:36 +0800444 except: # pylint: disable=W0702
445 logging.exception('Error retrieving EC console log')
446
Dean Liao88b93192014-10-23 19:37:41 +0800447 @staticmethod
448 def log_ec_panic_info():
449 """Logs EC panic info into logging.info.
450
451 It logs an error message in logging.exception if an exception is raised
452 when getting EC panic info.
453 For unsupported device, it logs unsupport message in logging.info
454
455 Returns:
456 EC panic info string.
457 """
Vic Yang079f9872013-07-01 11:32:00 +0800458 try:
Hung-Te Linb6287242016-05-18 14:39:05 +0800459 ec_panic_info = device_utils.CreateDUTInterface().ec.GetECPanicInfo()
Vic Yang079f9872013-07-01 11:32:00 +0800460 logging.info('EC panic info after reboot:\n%s\n', ec_panic_info)
Dean Liao88b93192014-10-23 19:37:41 +0800461 return ec_panic_info
462 except NotImplementedError:
463 logging.info('EC panic info is not supported')
Vic Yang079f9872013-07-01 11:32:00 +0800464 except: # pylint: disable=W0702
465 logging.exception('Error retrieving EC panic info')
466
Ricky Liang48e47f92014-02-26 19:31:51 +0800467 def shutdown(self, operation):
468 """Starts shutdown procedure.
469
470 Args:
Vic (Chun-Ju) Yang05b0d952014-04-28 17:39:09 +0800471 operation: The shutdown operation (reboot, full_reboot, or halt).
Ricky Liang48e47f92014-02-26 19:31:51 +0800472 """
473 active_tests = []
474 for test in self.test_list.walk():
475 if not test.is_leaf():
476 continue
477
478 test_state = test.get_state()
479 if test_state.status == TestState.ACTIVE:
480 active_tests.append(test)
481
Ricky Liang48e47f92014-02-26 19:31:51 +0800482 if not (len(active_tests) == 1 and
483 isinstance(active_tests[0], factory.ShutdownStep)):
484 logging.error(
485 'Calling Goofy shutdown outside of the shutdown factory test')
486 return
487
488 logging.info('Start Goofy shutdown (%s)', operation)
489 # Save pending test list in the state server
490 self.state_instance.set_shared_data(
491 'tests_after_shutdown',
492 [t.path for t in self.tests_to_run])
493 # Save shutdown time
494 self.state_instance.set_shared_data('shutdown_time', time.time())
495
496 with self.env.lock:
497 self.event_log.Log('shutdown', operation=operation)
498 shutdown_result = self.env.shutdown(operation)
499 if shutdown_result:
500 # That's all, folks!
Peter Ammon1e1ec572014-06-26 17:56:32 -0700501 self.run_enqueue(None)
Ricky Liang48e47f92014-02-26 19:31:51 +0800502 else:
503 # Just pass (e.g., in the chroot).
504 self.state_instance.set_shared_data('tests_after_shutdown', None)
505 # Send event with no fields to indicate that there is no
506 # longer a pending shutdown.
507 self.event_client.post_event(Event(Event.Type.PENDING_SHUTDOWN))
508
509 def handle_shutdown_complete(self, test):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800510 """Handles the case where a shutdown was detected during a shutdown step.
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800511
Ricky Liang6fe218c2013-12-27 15:17:17 +0800512 Args:
513 test: The ShutdownStep.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800514 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800515 test_state = test.update_state(increment_shutdown_count=1)
516 logging.info('Detected shutdown (%d of %d)',
Ricky Liang48e47f92014-02-26 19:31:51 +0800517 test_state.shutdown_count, test.iterations)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800518
Ricky Liang48e47f92014-02-26 19:31:51 +0800519 # Insert current shutdown test at the front of the list of tests to run
520 # after shutdown. This is to continue on post-shutdown verification in the
521 # shutdown step.
522 tests_after_shutdown = self.state_instance.get_shared_data(
523 'tests_after_shutdown', optional=True)
524 if not tests_after_shutdown:
525 self.state_instance.set_shared_data('tests_after_shutdown', [test.path])
526 elif isinstance(tests_after_shutdown, list):
527 self.state_instance.set_shared_data(
528 'tests_after_shutdown', [test.path] + tests_after_shutdown)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800529
Ricky Liang48e47f92014-02-26 19:31:51 +0800530 # Set 'post_shutdown' to inform shutdown test that a shutdown just occurred.
Ricky Liangb7eb8772014-09-15 18:05:22 +0800531 self.state_instance.set_shared_data(
532 state.POST_SHUTDOWN_TAG % test.path,
533 self.state_instance.get_test_state(test.path).invocation)
Jon Salz258a40c2012-04-19 12:34:01 +0800534
Jon Salz0697cbf2012-07-04 15:14:04 +0800535 def init_states(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800536 """Initializes all states on startup."""
Jon Salz0697cbf2012-07-04 15:14:04 +0800537 for test in self.test_list.get_all_tests():
538 # Make sure the state server knows about all the tests,
539 # defaulting to an untested state.
540 test.update_state(update_parent=False, visible=False)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800541
Jon Salz0697cbf2012-07-04 15:14:04 +0800542 var_log_messages = None
Vic Yanga9c32212012-08-16 20:07:54 +0800543 mosys_log = None
Vic Yange4c275d2012-08-28 01:50:20 +0800544 ec_console_log = None
Vic Yang079f9872013-07-01 11:32:00 +0800545 ec_panic_info = None
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800546
Jon Salz0697cbf2012-07-04 15:14:04 +0800547 # Any 'active' tests should be marked as failed now.
548 for test in self.test_list.walk():
Jon Salza6711d72012-07-18 14:33:03 +0800549 if not test.is_leaf():
550 # Don't bother with parents; they will be updated when their
551 # children are updated.
552 continue
553
Jon Salz0697cbf2012-07-04 15:14:04 +0800554 test_state = test.get_state()
555 if test_state.status != TestState.ACTIVE:
556 continue
557 if isinstance(test, factory.ShutdownStep):
558 # Shutdown while the test was active - that's good.
Ricky Liang48e47f92014-02-26 19:31:51 +0800559 self.handle_shutdown_complete(test)
Jon Salz0697cbf2012-07-04 15:14:04 +0800560 else:
561 # Unexpected shutdown. Grab /var/log/messages for context.
562 if var_log_messages is None:
563 try:
564 var_log_messages = (
Hung-Te Lin1a4e30c2016-01-08 23:25:10 +0800565 sys_utils.GetVarLogMessagesBeforeReboot())
Jon Salz0697cbf2012-07-04 15:14:04 +0800566 # Write it to the log, to make it easier to
567 # correlate with /var/log/messages.
568 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +0800569 'Unexpected shutdown. '
570 'Tail of /var/log/messages before last reboot:\n'
571 '%s', ('\n'.join(
572 ' ' + x for x in var_log_messages)))
Jon Salz0697cbf2012-07-04 15:14:04 +0800573 except: # pylint: disable=W0702
574 logging.exception('Unable to grok /var/log/messages')
575 var_log_messages = []
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800576
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800577 if mosys_log is None and not sys_utils.InChroot():
Jon Salz008f4ea2012-08-28 05:39:45 +0800578 try:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800579 mosys_log = process_utils.Spawn(
Jon Salz008f4ea2012-08-28 05:39:45 +0800580 ['mosys', 'eventlog', 'list'],
581 read_stdout=True, log_stderr_on_error=True).stdout_data
582 # Write it to the log also.
583 logging.info('System eventlog from mosys:\n%s\n', mosys_log)
584 except: # pylint: disable=W0702
585 logging.exception('Unable to read mosys eventlog')
Vic Yanga9c32212012-08-16 20:07:54 +0800586
Vic Yange4c275d2012-08-28 01:50:20 +0800587 if ec_console_log is None:
Dean Liao88b93192014-10-23 19:37:41 +0800588 ec_console_log = self.log_ec_console()
Vic Yange4c275d2012-08-28 01:50:20 +0800589
Vic Yang079f9872013-07-01 11:32:00 +0800590 if ec_panic_info is None:
Dean Liao88b93192014-10-23 19:37:41 +0800591 ec_panic_info = self.log_ec_panic_info()
Vic Yang079f9872013-07-01 11:32:00 +0800592
Jon Salz0697cbf2012-07-04 15:14:04 +0800593 error_msg = 'Unexpected shutdown while test was running'
Chun-Ta Lin53cbbd52016-06-08 21:42:19 +0800594 # TODO(itspeter): Add testlog to collect expired session infos.
Jon Salz0697cbf2012-07-04 15:14:04 +0800595 self.event_log.Log('end_test',
Ricky Liang45c73e72015-01-15 15:00:30 +0800596 path=test.path,
597 status=TestState.FAILED,
598 invocation=test.get_state().invocation,
599 error_msg=error_msg,
600 var_log_messages='\n'.join(var_log_messages),
601 mosys_log=mosys_log)
Jon Salz0697cbf2012-07-04 15:14:04 +0800602 test.update_state(
Ricky Liang45c73e72015-01-15 15:00:30 +0800603 status=TestState.FAILED,
604 error_msg=error_msg)
Chun-Ta Lin87c2dac2015-05-02 01:35:01 -0700605 # Trigger the OnTestFailure callback.
Claire Changd1961a22015-08-05 16:15:55 +0800606 self.run_queue.put(lambda: self.test_fail(test))
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800607
Jon Salz50efe942012-07-26 11:54:10 +0800608 if not test.never_fails:
609 # For "never_fails" tests (such as "Start"), don't cancel
610 # pending tests, since reboot is expected.
611 factory.console.info('Unexpected shutdown while test %s '
612 'running; cancelling any pending tests',
613 test.path)
614 self.state_instance.set_shared_data('tests_after_shutdown', [])
Jon Salz69806bb2012-07-20 18:05:02 +0800615
Jon Salz008f4ea2012-08-28 05:39:45 +0800616 self.update_skipped_tests()
617
618 def update_skipped_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800619 """Updates skipped states based on run_if."""
Jon Salz885dcac2013-07-23 16:39:50 +0800620 env = TestArgEnv()
Ricky Liang45c73e72015-01-15 15:00:30 +0800621
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800622 def _evaluate_skip_from_run_if(test):
623 """Returns the run_if evaluation of the test.
624
Wei-Han Chen7f3877d2016-10-07 22:41:27 +0800625 Evaluates test's run_if argument to decide skipping the test or not. If
626 run_if argument is not set, the test will never be skipped.
627
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800628 Args:
629 test: A FactoryTest object.
630
631 Returns:
Wei-Han Chen7f3877d2016-10-07 22:41:27 +0800632 True if this test should be skipped, otherwise False.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800633 """
634 value = None
635 if test.run_if_expr:
636 try:
637 value = test.run_if_expr(env)
638 except: # pylint: disable=W0702
639 logging.exception('Unable to evaluate run_if expression for %s',
640 test.path)
641 # But keep going; we have no choice. This will end up
642 # always activating the test.
Wei-Han Chen7f3877d2016-10-07 22:41:27 +0800643 return False
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800644 elif test.run_if_table_name:
645 try:
646 aux = shopfloor.get_selected_aux_data(test.run_if_table_name)
647 value = aux.get(test.run_if_col)
648 except ValueError:
Wei-Han Chen7f3877d2016-10-07 22:41:27 +0800649 # Cannot find corresponding value, use default value (None)
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800650 pass
Wei-Han Chen7f3877d2016-10-07 22:41:27 +0800651 else: # run_if is not set
652 return False
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800653
Wei-Han Chen7f3877d2016-10-07 22:41:27 +0800654 return (not value) ^ t.run_if_not
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800655
656 # Gets all run_if evaluation, and stores results in skip_map.
657 skip_map = dict()
Jon Salz008f4ea2012-08-28 05:39:45 +0800658 for t in self.test_list.walk():
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800659 skip_map[t.path] = _evaluate_skip_from_run_if(t)
Jon Salz885dcac2013-07-23 16:39:50 +0800660
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800661 # Propagates the skip value from root of tree and updates skip_map.
662 def _update_skip_map_from_node(test, skip_from_parent):
663 """Updates skip_map from a given node.
Jon Salz885dcac2013-07-23 16:39:50 +0800664
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800665 Given a FactoryTest node and the skip value from parent, updates the
666 skip value of current node in the skip_map if skip value from parent is
667 True. If this node has children, recursively propagate this value to all
668 its children, that is, all its subtests.
669 Note that this function only updates value in skip_map, not the actual
670 test_list tree.
Jon Salz008f4ea2012-08-28 05:39:45 +0800671
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800672 Args:
673 test: The given FactoryTest object. It is a node in the test_list tree.
674 skip_from_parent: The skip value which propagates from the parent of
675 input node.
676 """
677 skip_this_tree = skip_from_parent or skip_map[test.path]
678 if skip_this_tree:
679 logging.info('Skip from node %r', test.path)
680 skip_map[test.path] = True
681 if test.is_leaf():
682 return
683 # Propagates skip value to its subtests
684 for subtest in test.subtests:
685 _update_skip_map_from_node(subtest, skip_this_tree)
686
687 _update_skip_map_from_node(self.test_list, False)
688
689 # Updates the skip value from skip_map to test_list tree. Also, updates test
690 # status if needed.
691 for t in self.test_list.walk():
692 skip = skip_map[t.path]
693 test_state = t.get_state()
694 if ((not skip) and
695 (test_state.status == TestState.PASSED) and
696 (test_state.error_msg == TestState.SKIPPED_MSG)):
697 # It was marked as skipped before, but now we need to run it.
698 # Mark as untested.
699 t.update_state(skip=skip, status=TestState.UNTESTED, error_msg='')
700 else:
701 t.update_state(skip=skip)
Jon Salz008f4ea2012-08-28 05:39:45 +0800702
Jon Salz0697cbf2012-07-04 15:14:04 +0800703 def handle_event(self, event):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800704 """Handles an event from the event server."""
Jon Salz0697cbf2012-07-04 15:14:04 +0800705 handler = self.event_handlers.get(event.type)
706 if handler:
707 handler(event)
708 else:
709 # We don't register handlers for all event types - just ignore
710 # this event.
711 logging.debug('Unbound event type %s', event.type)
Jon Salz4f6c7172012-06-11 20:45:36 +0800712
Vic Yangaabf9fd2013-04-09 18:56:13 +0800713 def check_critical_factory_note(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800714 """Returns True if the last factory note is critical."""
Vic Yangaabf9fd2013-04-09 18:56:13 +0800715 notes = self.state_instance.get_shared_data('factory_note', True)
716 return notes and notes[-1]['level'] == 'CRITICAL'
717
Hung-Te Linef7f2be2015-07-20 20:38:51 +0800718 def schedule_restart(self):
719 """Schedules a restart event when any invocation is completed."""
720 self.is_restart_requested = True
721
722 def invocation_completion(self):
723 """Callback when an invocation is completed."""
724 if self.is_restart_requested:
725 logging.info('Restart by scheduled event.')
726 self.is_restart_requested = False
727 self.restart_tests()
728 else:
729 self.run_next_test()
730
Jon Salz0697cbf2012-07-04 15:14:04 +0800731 def run_next_test(self):
henryhsu4cc6b022014-04-22 17:12:42 +0800732 """Runs the next eligible test (or tests) in self.tests_to_run.
733
734 We have three kinds of the next eligible test:
735 1. normal
736 2. backgroundable
737 3. force_background
738
739 And we have four situations of the ongoing invocations:
740 a. only a running normal test
741 b. all running tests are backgroundable
742 c. all running tests are force_background
743 d. all running tests are any combination of backgroundable and
744 force_background
745
746 When a test would like to be run, it must follow the rules:
747 [1] cannot run with [abd]
748 [2] cannot run with [a]
749 All the other combinations are allowed
750 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800751 self.reap_completed_tests()
Vic Yangaabf9fd2013-04-09 18:56:13 +0800752 if self.tests_to_run and self.check_critical_factory_note():
753 self.tests_to_run.clear()
754 return
Jon Salz0697cbf2012-07-04 15:14:04 +0800755 while self.tests_to_run:
Ricky Liang6fe218c2013-12-27 15:17:17 +0800756 logging.debug('Tests to run: %s', [x.path for x in self.tests_to_run])
Jon Salz94eb56f2012-06-12 18:01:12 +0800757
Jon Salz0697cbf2012-07-04 15:14:04 +0800758 test = self.tests_to_run[0]
Jon Salz94eb56f2012-06-12 18:01:12 +0800759
Jon Salz0697cbf2012-07-04 15:14:04 +0800760 if test in self.invocations:
761 logging.info('Next test %s is already running', test.path)
762 self.tests_to_run.popleft()
763 return
Jon Salz94eb56f2012-06-12 18:01:12 +0800764
Jon Salza1412922012-07-23 16:04:17 +0800765 for requirement in test.require_run:
766 for i in requirement.test.walk():
767 if i.get_state().status == TestState.ACTIVE:
Jon Salz304a75d2012-07-06 11:14:15 +0800768 logging.info('Waiting for active test %s to complete '
Jon Salza1412922012-07-23 16:04:17 +0800769 'before running %s', i.path, test.path)
Jon Salz304a75d2012-07-06 11:14:15 +0800770 return
771
henryhsu4cc6b022014-04-22 17:12:42 +0800772 def is_normal_test(test):
773 return not (test.backgroundable or test.force_background)
774
775 # [1] cannot run with [abd].
776 if self.invocations and is_normal_test(test) and any(
777 [not x.force_background for x in self.invocations]):
778 logging.info('Waiting for non-force_background tests to '
779 'complete before running %s', test.path)
780 return
781
782 # [2] cannot run with [a].
783 if self.invocations and test.backgroundable and any(
784 [is_normal_test(x) for x in self.invocations]):
785 logging.info('Waiting for normal tests to '
786 'complete before running %s', test.path)
Jon Salz0697cbf2012-07-04 15:14:04 +0800787 return
Jon Salz94eb56f2012-06-12 18:01:12 +0800788
Jon Salz3e6f5202012-10-15 15:08:29 +0800789 if test.get_state().skip:
790 factory.console.info('Skipping test %s', test.path)
791 test.update_state(status=TestState.PASSED,
792 error_msg=TestState.SKIPPED_MSG)
793 self.tests_to_run.popleft()
794 continue
795
Jon Salz0697cbf2012-07-04 15:14:04 +0800796 self.tests_to_run.popleft()
Jon Salz94eb56f2012-06-12 18:01:12 +0800797
Jon Salz304a75d2012-07-06 11:14:15 +0800798 untested = set()
Jon Salza1412922012-07-23 16:04:17 +0800799 for requirement in test.require_run:
800 for i in requirement.test.walk():
801 if i == test:
Jon Salz304a75d2012-07-06 11:14:15 +0800802 # We've hit this test itself; stop checking
803 break
Jon Salza1412922012-07-23 16:04:17 +0800804 if ((i.get_state().status == TestState.UNTESTED) or
805 (requirement.passed and i.get_state().status !=
806 TestState.PASSED)):
Jon Salz304a75d2012-07-06 11:14:15 +0800807 # Found an untested test; move on to the next
808 # element in require_run.
Jon Salza1412922012-07-23 16:04:17 +0800809 untested.add(i)
Jon Salz304a75d2012-07-06 11:14:15 +0800810 break
811
812 if untested:
813 untested_paths = ', '.join(sorted([x.path for x in untested]))
814 if self.state_instance.get_shared_data('engineering_mode',
815 optional=True):
816 # In engineering mode, we'll let it go.
817 factory.console.warn('In engineering mode; running '
818 '%s even though required tests '
819 '[%s] have not completed',
820 test.path, untested_paths)
821 else:
822 # Not in engineering mode; mark it failed.
823 error_msg = ('Required tests [%s] have not been run yet'
824 % untested_paths)
825 factory.console.error('Not running %s: %s',
826 test.path, error_msg)
827 test.update_state(status=TestState.FAILED,
828 error_msg=error_msg)
829 continue
830
Ricky Liang48e47f92014-02-26 19:31:51 +0800831 if (isinstance(test, factory.ShutdownStep) and
Ricky Liangb7eb8772014-09-15 18:05:22 +0800832 self.state_instance.get_shared_data(
833 state.POST_SHUTDOWN_TAG % test.path, optional=True)):
Ricky Liang48e47f92014-02-26 19:31:51 +0800834 # Invoking post shutdown method of shutdown test. We should retain the
835 # iterations_left and retries_left of the original test state.
836 test_state = self.state_instance.get_test_state(test.path)
837 self._run_test(test, test_state.iterations_left,
838 test_state.retries_left)
839 else:
840 # Starts a new test run; reset iterations and retries.
841 self._run_test(test, test.iterations, test.retries)
Jon Salz1acc8742012-07-17 17:45:55 +0800842
Cheng-Yi Chiangce05c002013-04-04 02:13:17 +0800843 def _run_test(self, test, iterations_left=None, retries_left=None):
Vic Yanga3cecf82014-12-26 00:44:21 -0800844 if not self._ui_initialized and not test.is_no_host():
845 self.init_ui()
Vic Yang08505c72015-01-06 17:01:53 -0800846 invoc = TestInvocation(
Hung-Te Linef7f2be2015-07-20 20:38:51 +0800847 self, test, on_completion=self.invocation_completion,
Claire Changd1961a22015-08-05 16:15:55 +0800848 on_test_failure=lambda: self.test_fail(test))
Jon Salz1acc8742012-07-17 17:45:55 +0800849 new_state = test.update_state(
Ricky Liang48e47f92014-02-26 19:31:51 +0800850 status=TestState.ACTIVE, increment_count=1, error_msg='',
851 invocation=invoc.uuid, iterations_left=iterations_left,
852 retries_left=retries_left,
853 visible=(self.visible_test == test))
Jon Salz1acc8742012-07-17 17:45:55 +0800854 invoc.count = new_state.count
855
856 self.invocations[test] = invoc
857 if self.visible_test is None and test.has_ui:
858 self.set_visible_test(test)
Vic Yang311ddb82012-09-26 12:08:28 +0800859 self.check_exclusive()
Jon Salz1acc8742012-07-17 17:45:55 +0800860 invoc.start()
Jon Salz5f2a0672012-05-22 17:14:06 +0800861
Vic Yang311ddb82012-09-26 12:08:28 +0800862 def check_exclusive(self):
Jon Salzce6a7f82013-06-10 18:22:54 +0800863 # alias since this is really long
864 EXCL_OPT = factory.FactoryTest.EXCLUSIVE_OPTIONS
865
Vic Yang311ddb82012-09-26 12:08:28 +0800866 current_exclusive_items = set([
Jon Salzce6a7f82013-06-10 18:22:54 +0800867 item for item in EXCL_OPT
Vic Yang311ddb82012-09-26 12:08:28 +0800868 if any([test.is_exclusive(item) for test in self.invocations])])
869
870 new_exclusive_items = current_exclusive_items - self.exclusive_items
Jon Salzce6a7f82013-06-10 18:22:54 +0800871 if EXCL_OPT.NETWORKING in new_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800872 logging.info('Disabling network')
873 self.connection_manager.DisableNetworking()
Jon Salzce6a7f82013-06-10 18:22:54 +0800874 if EXCL_OPT.CHARGER in new_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800875 logging.info('Stop controlling charger')
876
877 new_non_exclusive_items = self.exclusive_items - current_exclusive_items
Jon Salzce6a7f82013-06-10 18:22:54 +0800878 if EXCL_OPT.NETWORKING in new_non_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800879 logging.info('Re-enabling network')
880 self.connection_manager.EnableNetworking()
Jon Salzce6a7f82013-06-10 18:22:54 +0800881 if EXCL_OPT.CHARGER in new_non_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800882 logging.info('Start controlling charger')
883
Jon Salzce6a7f82013-06-10 18:22:54 +0800884 if self.cpufreq_manager:
885 enabled = EXCL_OPT.CPUFREQ not in current_exclusive_items
886 try:
887 self.cpufreq_manager.SetEnabled(enabled)
888 except: # pylint: disable=W0702
889 logging.exception('Unable to %s cpufreq services',
890 'enable' if enabled else 'disable')
891
Ricky Liang0f9978e2015-01-30 08:19:17 +0000892 # Only adjust charge state if not excluded
893 if (EXCL_OPT.CHARGER not in current_exclusive_items and
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800894 not sys_utils.InChroot()):
Ricky Liang0f9978e2015-01-30 08:19:17 +0000895 if self.charge_manager:
Cheng-Yi Chiangd8186952013-04-04 23:41:14 +0800896 self.charge_manager.AdjustChargeState()
Vic Yang311ddb82012-09-26 12:08:28 +0800897
898 self.exclusive_items = current_exclusive_items
Jon Salz5da61e62012-05-31 13:06:22 +0800899
Dean Liao88b93192014-10-23 19:37:41 +0800900 def charge(self):
901 """Charges the board.
902
903 It won't try again if last time SetChargeState raised an exception.
904 """
905 if not self._can_charge:
906 return
907
908 try:
Ricky Liang9ac35e02015-01-30 16:01:32 +0800909 if self.charge_manager:
910 self.charge_manager.StartCharging()
911 else:
Hung-Te Lin6a72c642015-12-13 22:09:09 +0800912 self.dut.power.SetChargeState(self.dut.power.ChargeState.CHARGE)
Dean Liao88b93192014-10-23 19:37:41 +0800913 except NotImplementedError:
914 logging.info('Charging is not supported')
915 self._can_charge = False
Hung-Te Linb6287242016-05-18 14:39:05 +0800916 except DeviceException:
Dean Liao88b93192014-10-23 19:37:41 +0800917 logging.exception('Unable to set charge state on this board')
918 self._can_charge = False
919
cychiang21886742012-07-05 15:16:32 +0800920 def check_for_updates(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800921 """Schedules an asynchronous check for updates if necessary."""
cychiang21886742012-07-05 15:16:32 +0800922 if not self.test_list.options.update_period_secs:
923 # Not enabled.
924 return
925
926 now = time.time()
927 if self.last_update_check and (
928 now - self.last_update_check <
929 self.test_list.options.update_period_secs):
930 # Not yet time for another check.
931 return
932
933 self.last_update_check = now
934
935 def handle_check_for_update(reached_shopfloor, md5sum, needs_update):
936 if reached_shopfloor:
937 new_update_md5sum = md5sum if needs_update else None
Hung-Te Line594e5d2015-12-16 02:36:05 +0800938 if self.dut.info.update_md5sum != new_update_md5sum:
cychiang21886742012-07-05 15:16:32 +0800939 logging.info('Received new update MD5SUM: %s', new_update_md5sum)
Hung-Te Line594e5d2015-12-16 02:36:05 +0800940 self.dut.info.Overrides('update_md5sum', new_update_md5sum)
Peter Ammon1e1ec572014-06-26 17:56:32 -0700941 self.run_enqueue(self.update_system_info)
Cheng-Yi Chiang194d3c02015-03-16 14:37:15 +0800942 else:
943 if not self._suppress_periodic_update_messages:
944 logging.warning('Suppress error messages for periodic update checking'
945 ' after the first one.')
946 self._suppress_periodic_update_messages = True
cychiang21886742012-07-05 15:16:32 +0800947
948 updater.CheckForUpdateAsync(
Ricky Liang45c73e72015-01-15 15:00:30 +0800949 handle_check_for_update,
Cheng-Yi Chiang194d3c02015-03-16 14:37:15 +0800950 self.test_list.options.shopfloor_timeout_secs,
951 self._suppress_periodic_update_messages)
cychiang21886742012-07-05 15:16:32 +0800952
Jon Salza6711d72012-07-18 14:33:03 +0800953 def cancel_pending_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800954 """Cancels any tests in the run queue."""
Jon Salza6711d72012-07-18 14:33:03 +0800955 self.run_tests([])
956
Ricky Liang4bff3e32014-02-20 18:46:11 +0800957 def restore_active_run_state(self):
958 """Restores active run id and the list of scheduled tests."""
959 self.run_id = self.state_instance.get_shared_data('run_id', optional=True)
960 self.scheduled_run_tests = self.state_instance.get_shared_data(
961 'scheduled_run_tests', optional=True)
962
963 def set_active_run_state(self):
964 """Sets active run id and the list of scheduled tests."""
965 self.run_id = str(uuid.uuid4())
966 self.scheduled_run_tests = [test.path for test in self.tests_to_run]
967 self.state_instance.set_shared_data('run_id', self.run_id)
968 self.state_instance.set_shared_data('scheduled_run_tests',
969 self.scheduled_run_tests)
970
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +0800971 def run_tests(self, subtrees, status_filter=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800972 """Runs tests under subtree.
Jon Salz258a40c2012-04-19 12:34:01 +0800973
Jon Salz0697cbf2012-07-04 15:14:04 +0800974 The tests are run in order unless one fails (then stops).
975 Backgroundable tests are run simultaneously; when a foreground test is
976 encountered, we wait for all active tests to finish before continuing.
Jon Salzb1b39092012-05-03 02:05:09 +0800977
Ricky Liang6fe218c2013-12-27 15:17:17 +0800978 Args:
979 subtrees: Node or nodes containing tests to run (may either be
980 a single test or a list). Duplicates will be ignored.
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +0800981 status_filter: List of available test states. Only run the tests which
982 states are in the list. Set to None if all test states are available.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800983 """
Hung-Te Lin410f70a2015-12-15 14:53:42 +0800984 self.dut.hooks.OnTestStart()
Vic Yang08505c72015-01-06 17:01:53 -0800985
Jon Salz0697cbf2012-07-04 15:14:04 +0800986 if type(subtrees) != list:
987 subtrees = [subtrees]
Jon Salz258a40c2012-04-19 12:34:01 +0800988
Jon Salz0697cbf2012-07-04 15:14:04 +0800989 # Nodes we've seen so far, to avoid duplicates.
990 seen = set()
Jon Salz94eb56f2012-06-12 18:01:12 +0800991
Jon Salz0697cbf2012-07-04 15:14:04 +0800992 self.tests_to_run = deque()
993 for subtree in subtrees:
994 for test in subtree.walk():
995 if test in seen:
996 continue
997 seen.add(test)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800998
Jon Salz0697cbf2012-07-04 15:14:04 +0800999 if not test.is_leaf():
1000 continue
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +08001001 if (status_filter is not None and
1002 test.get_state().status not in status_filter):
Jon Salz0697cbf2012-07-04 15:14:04 +08001003 continue
1004 self.tests_to_run.append(test)
Ricky Liang4bff3e32014-02-20 18:46:11 +08001005 if subtrees:
1006 self.set_active_run_state()
Jon Salz0697cbf2012-07-04 15:14:04 +08001007 self.run_next_test()
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001008
Jon Salz0697cbf2012-07-04 15:14:04 +08001009 def reap_completed_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001010 """Removes completed tests from the set of active tests.
Jon Salz0697cbf2012-07-04 15:14:04 +08001011
1012 Also updates the visible test if it was reaped.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001013 """
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001014 test_completed = False
Jon Salz0697cbf2012-07-04 15:14:04 +08001015 for t, v in dict(self.invocations).iteritems():
1016 if v.is_completed():
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001017 test_completed = True
Jon Salz1acc8742012-07-17 17:45:55 +08001018 new_state = t.update_state(**v.update_state_on_completion)
Jon Salz0697cbf2012-07-04 15:14:04 +08001019 del self.invocations[t]
1020
Johny Lin62ed2a32015-05-13 11:57:12 +08001021 # Stop on failure if flag is true and there is no retry chances.
Chun-Ta Lin54e17e42012-09-06 22:05:13 +08001022 if (self.test_list.options.stop_on_failure and
Johny Lin62ed2a32015-05-13 11:57:12 +08001023 new_state.retries_left < 0 and
Chun-Ta Lin54e17e42012-09-06 22:05:13 +08001024 new_state.status == TestState.FAILED):
1025 # Clean all the tests to cause goofy to stop.
1026 self.tests_to_run = []
Ricky Liang45c73e72015-01-15 15:00:30 +08001027 factory.console.info('Stop on failure triggered. Empty the queue.')
Chun-Ta Lin54e17e42012-09-06 22:05:13 +08001028
Jon Salz1acc8742012-07-17 17:45:55 +08001029 if new_state.iterations_left and new_state.status == TestState.PASSED:
1030 # Play it again, Sam!
1031 self._run_test(t)
Cheng-Yi Chiangce05c002013-04-04 02:13:17 +08001032 # new_state.retries_left is obtained after update.
1033 # For retries_left == 0, test can still be run for the last time.
1034 elif (new_state.retries_left >= 0 and
1035 new_state.status == TestState.FAILED):
1036 # Still have to retry, Sam!
1037 self._run_test(t)
Jon Salz1acc8742012-07-17 17:45:55 +08001038
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001039 if test_completed:
Vic Yangf01c59f2013-04-19 17:37:56 +08001040 self.log_watcher.KickWatchThread()
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001041
Jon Salz0697cbf2012-07-04 15:14:04 +08001042 if (self.visible_test is None or
Jon Salz85a39882012-07-05 16:45:04 +08001043 self.visible_test not in self.invocations):
Jon Salz0697cbf2012-07-04 15:14:04 +08001044 self.set_visible_test(None)
1045 # Make the first running test, if any, the visible test
1046 for t in self.test_list.walk():
1047 if t in self.invocations:
1048 self.set_visible_test(t)
1049 break
1050
Jon Salz6dc031d2013-06-19 13:06:23 +08001051 def kill_active_tests(self, abort, root=None, reason=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001052 """Kills and waits for all active tests.
Jon Salz0697cbf2012-07-04 15:14:04 +08001053
Jon Salz85a39882012-07-05 16:45:04 +08001054 Args:
1055 abort: True to change state of killed tests to FAILED, False for
Jon Salz0697cbf2012-07-04 15:14:04 +08001056 UNTESTED.
Jon Salz85a39882012-07-05 16:45:04 +08001057 root: If set, only kills tests with root as an ancestor.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001058 reason: If set, the abort reason.
1059 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001060 self.reap_completed_tests()
1061 for test, invoc in self.invocations.items():
Jon Salz85a39882012-07-05 16:45:04 +08001062 if root and not test.has_ancestor(root):
1063 continue
1064
Ricky Liang45c73e72015-01-15 15:00:30 +08001065 factory.console.info('Killing active test %s...', test.path)
Jon Salz6dc031d2013-06-19 13:06:23 +08001066 invoc.abort_and_join(reason)
Ricky Liang45c73e72015-01-15 15:00:30 +08001067 factory.console.info('Killed %s', test.path)
Jon Salz1acc8742012-07-17 17:45:55 +08001068 test.update_state(**invoc.update_state_on_completion)
Jon Salz0697cbf2012-07-04 15:14:04 +08001069 del self.invocations[test]
Jon Salz1acc8742012-07-17 17:45:55 +08001070
Jon Salz0697cbf2012-07-04 15:14:04 +08001071 if not abort:
1072 test.update_state(status=TestState.UNTESTED)
1073 self.reap_completed_tests()
1074
Jon Salz6dc031d2013-06-19 13:06:23 +08001075 def stop(self, root=None, fail=False, reason=None):
1076 self.kill_active_tests(fail, root, reason)
Jon Salz85a39882012-07-05 16:45:04 +08001077 # Remove any tests in the run queue under the root.
1078 self.tests_to_run = deque([x for x in self.tests_to_run
1079 if root and not x.has_ancestor(root)])
1080 self.run_next_test()
Jon Salz0697cbf2012-07-04 15:14:04 +08001081
Jon Salz4712ac72013-02-07 17:12:05 +08001082 def clear_state(self, root=None):
Jon Salzd7550792013-07-12 05:49:27 +08001083 if root is None:
1084 root = self.test_list
Jon Salz6dc031d2013-06-19 13:06:23 +08001085 self.stop(root, reason='Clearing test state')
Jon Salz4712ac72013-02-07 17:12:05 +08001086 for f in root.walk():
1087 if f.is_leaf():
1088 f.update_state(status=TestState.UNTESTED)
1089
Jon Salz6dc031d2013-06-19 13:06:23 +08001090 def abort_active_tests(self, reason=None):
1091 self.kill_active_tests(True, reason=reason)
Jon Salz0697cbf2012-07-04 15:14:04 +08001092
1093 def main(self):
Jon Salzeff94182013-06-19 15:06:28 +08001094 syslog.openlog('goofy')
1095
Jon Salz0697cbf2012-07-04 15:14:04 +08001096 try:
Jon Salzd7550792013-07-12 05:49:27 +08001097 self.status = Status.INITIALIZING
Jon Salz0697cbf2012-07-04 15:14:04 +08001098 self.init()
1099 self.event_log.Log('goofy_init',
Ricky Liang45c73e72015-01-15 15:00:30 +08001100 success=True)
Chun-Ta Lin53cbbd52016-06-08 21:42:19 +08001101 testlog.Log(
Joel Kitching9eb203a2016-04-21 15:36:30 +08001102 testlog.StationInit({
Chun-Ta Lin53cbbd52016-06-08 21:42:19 +08001103 'stationDeviceId': testlog_goofy.GetDeviceID(),
Joel Kitching21bc69b2016-07-13 08:29:52 -07001104 'stationInstallationId': testlog_goofy.GetInstallationID(),
Chun-Ta Lin53cbbd52016-06-08 21:42:19 +08001105 'count': testlog_goofy.GetInitCount(),
Joel Kitching9eb203a2016-04-21 15:36:30 +08001106 'success': True}))
Jon Salz0697cbf2012-07-04 15:14:04 +08001107 except:
Joel Kitching9eb203a2016-04-21 15:36:30 +08001108 try:
1109 if self.event_log:
Jon Salz0697cbf2012-07-04 15:14:04 +08001110 self.event_log.Log('goofy_init',
Ricky Liang45c73e72015-01-15 15:00:30 +08001111 success=False,
1112 trace=traceback.format_exc())
Chun-Ta Lin53cbbd52016-06-08 21:42:19 +08001113 if self.testlog:
1114 testlog.Log(
Joel Kitching9eb203a2016-04-21 15:36:30 +08001115 testlog.StationInit({
Chun-Ta Lin53cbbd52016-06-08 21:42:19 +08001116 'stationDeviceId': testlog_goofy.GetDeviceID(),
Joel Kitching21bc69b2016-07-13 08:29:52 -07001117 'stationInstallationId': testlog_goofy.GetInstallationID(),
Chun-Ta Lin53cbbd52016-06-08 21:42:19 +08001118 'count': testlog_goofy.GetInitCount(),
Joel Kitching9eb203a2016-04-21 15:36:30 +08001119 'success': False,
1120 'failureMessage': traceback.format_exc()}))
1121 except: # pylint: disable=W0702
1122 pass
Jon Salz0697cbf2012-07-04 15:14:04 +08001123 raise
1124
Jon Salzd7550792013-07-12 05:49:27 +08001125 self.status = Status.RUNNING
Jon Salzeff94182013-06-19 15:06:28 +08001126 syslog.syslog('Goofy (factory test harness) starting')
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001127 syslog.syslog('Boot sequence = %d' % GetBootSequence())
Chun-Ta Lin53cbbd52016-06-08 21:42:19 +08001128 syslog.syslog('Goofy init count = %d' % testlog_goofy.GetInitCount())
Jon Salz0697cbf2012-07-04 15:14:04 +08001129 self.run()
1130
1131 def update_system_info(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001132 """Updates system info."""
Hung-Te Line594e5d2015-12-16 02:36:05 +08001133 info = self.dut.info.GetAll()
1134 self.state_instance.set_shared_data('system_info', info)
Jon Salz0697cbf2012-07-04 15:14:04 +08001135 self.event_client.post_event(Event(Event.Type.SYSTEM_INFO,
Hung-Te Line594e5d2015-12-16 02:36:05 +08001136 system_info=info))
1137 logging.info('System info: %r', info)
Jon Salz0697cbf2012-07-04 15:14:04 +08001138
Jon Salzeb42f0d2012-07-27 19:14:04 +08001139 def update_factory(self, auto_run_on_restart=False, post_update_hook=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001140 """Commences updating factory software.
Jon Salzeb42f0d2012-07-27 19:14:04 +08001141
1142 Args:
1143 auto_run_on_restart: Auto-run when the machine comes back up.
1144 post_update_hook: Code to call after update but immediately before
1145 restart.
1146
1147 Returns:
1148 Never if the update was successful (we just reboot).
1149 False if the update was unnecessary (no update available).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001150 """
Jon Salz6dc031d2013-06-19 13:06:23 +08001151 self.kill_active_tests(False, reason='Factory software update')
Jon Salza6711d72012-07-18 14:33:03 +08001152 self.cancel_pending_tests()
Jon Salz0697cbf2012-07-04 15:14:04 +08001153
Jon Salz5c344f62012-07-13 14:31:16 +08001154 def pre_update_hook():
1155 if auto_run_on_restart:
1156 self.state_instance.set_shared_data('tests_after_shutdown',
1157 FORCE_AUTO_RUN)
1158 self.state_instance.close()
1159
Jon Salzeb42f0d2012-07-27 19:14:04 +08001160 if updater.TryUpdate(pre_update_hook=pre_update_hook):
1161 if post_update_hook:
1162 post_update_hook()
1163 self.env.shutdown('reboot')
Jon Salz0697cbf2012-07-04 15:14:04 +08001164
Ricky Liang8fecf412014-05-22 10:56:14 +08001165 def handle_sigint(self, dummy_signum, dummy_frame): # pylint: disable=W0613
Jon Salz77c151e2012-08-28 07:20:37 +08001166 logging.error('Received SIGINT')
Peter Ammon1e1ec572014-06-26 17:56:32 -07001167 self.run_enqueue(None)
Jon Salz77c151e2012-08-28 07:20:37 +08001168 raise KeyboardInterrupt()
1169
Ricky Liang8fecf412014-05-22 10:56:14 +08001170 def handle_sigterm(self, dummy_signum, dummy_frame): # pylint: disable=W0613
1171 logging.error('Received SIGTERM')
Hung-Te Lin94ca4742014-07-09 20:13:50 +08001172 self.env.terminate()
1173 self.run_queue.put(None)
Ricky Liang8fecf412014-05-22 10:56:14 +08001174 raise RuntimeError('Received SIGTERM')
1175
Jon Salze12c2b32013-06-25 16:24:34 +08001176 def find_kcrashes(self):
1177 """Finds kcrash files, logs them, and marks them as seen."""
1178 seen_crashes = set(
1179 self.state_instance.get_shared_data('seen_crashes', optional=True)
1180 or [])
1181
1182 for path in glob.glob('/var/spool/crash/*'):
1183 if not os.path.isfile(path):
1184 continue
1185 if path in seen_crashes:
1186 continue
1187 try:
1188 stat = os.stat(path)
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001189 mtime = time_utils.TimeString(stat.st_mtime)
Jon Salze12c2b32013-06-25 16:24:34 +08001190 logging.info(
1191 'Found new crash file %s (%d bytes at %s)',
1192 path, stat.st_size, mtime)
1193 extra_log_args = {}
1194
1195 try:
1196 _, ext = os.path.splitext(path)
1197 if ext in ['.kcrash', '.meta']:
1198 ext = ext.replace('.', '')
1199 with open(path) as f:
1200 data = f.read(MAX_CRASH_FILE_SIZE)
1201 tell = f.tell()
1202 logging.info(
1203 'Contents of %s%s:%s',
1204 path,
1205 ('' if tell == stat.st_size
1206 else '(truncated to %d bytes)' % MAX_CRASH_FILE_SIZE),
1207 ('\n' + data).replace('\n', '\n ' + ext + '> '))
1208 extra_log_args['data'] = data
1209
1210 # Copy to /var/factory/kcrash for posterity
Joel Kitching625ff0f2016-05-16 14:59:40 -07001211 kcrash_dir = paths.GetFactoryRoot('kcrash')
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001212 file_utils.TryMakeDirs(kcrash_dir)
Jon Salze12c2b32013-06-25 16:24:34 +08001213 shutil.copy(path, kcrash_dir)
1214 logging.info('Copied to %s',
1215 os.path.join(kcrash_dir, os.path.basename(path)))
1216 finally:
1217 # Even if something goes wrong with the above, still try to
1218 # log to event log
1219 self.event_log.Log('crash_file',
1220 path=path, size=stat.st_size, mtime=mtime,
1221 **extra_log_args)
1222 except: # pylint: disable=W0702
1223 logging.exception('Unable to handle crash files %s', path)
1224 seen_crashes.add(path)
1225
1226 self.state_instance.set_shared_data('seen_crashes', list(seen_crashes))
1227
Jon Salz128b0932013-07-03 16:55:26 +08001228 def GetTestList(self, test_list_id):
1229 """Returns the test list with the given ID.
1230
1231 Raises:
1232 TestListError: The test list ID is not valid.
1233 """
1234 try:
1235 return self.test_lists[test_list_id]
1236 except KeyError:
1237 raise test_lists.TestListError(
1238 '%r is not a valid test list ID (available IDs are [%s])' % (
1239 test_list_id, ', '.join(sorted(self.test_lists.keys()))))
1240
1241 def InitTestLists(self):
Joel Kitching50a63ea2016-02-22 13:15:09 +08001242 """Reads in all test lists and sets the active test list.
1243
1244 Returns:
1245 True if the active test list could be set, False if failed.
1246 """
1247 startup_errors = []
1248 self.test_lists, failed_files = test_lists.BuildAllTestLists(
Ricky Liang27051552014-05-04 14:22:26 +08001249 force_generic=(self.options.automation_mode is not None))
Jon Salzd7550792013-07-12 05:49:27 +08001250 logging.info('Loaded test lists: [%s]',
1251 test_lists.DescribeTestLists(self.test_lists))
Jon Salz128b0932013-07-03 16:55:26 +08001252
Joel Kitching50a63ea2016-02-22 13:15:09 +08001253 # Check for any syntax errors in test list files.
1254 if failed_files:
1255 logging.info('Failed test list files: [%s]',
1256 ' '.join(failed_files.keys()))
1257 for f, exc_info in failed_files.iteritems():
1258 logging.error('Error in test list file: %s', f,
1259 exc_info=exc_info)
1260
1261 # Limit the stack trace to the very last entry.
1262 exc_type, exc_value, exc_traceback = exc_info
1263 while exc_traceback and exc_traceback.tb_next:
1264 exc_traceback = exc_traceback.tb_next
1265
1266 exc_string = ''.join(
1267 traceback.format_exception(
1268 exc_type, exc_value, exc_traceback)).rstrip()
1269 startup_errors.append('Error in test list file (%s):\n%s'
1270 % (f, exc_string))
1271
Jon Salz128b0932013-07-03 16:55:26 +08001272 if not self.options.test_list:
1273 self.options.test_list = test_lists.GetActiveTestListId()
1274
Joel Kitching50a63ea2016-02-22 13:15:09 +08001275 # Check for a non-existent test list ID.
1276 try:
Wei-Han Chen84fee7c2016-08-26 21:56:25 +08001277 self.test_list = self.GetTestList(self.options.test_list)
Joel Kitching50a63ea2016-02-22 13:15:09 +08001278 logging.info('Active test list: %s', self.test_list.test_list_id)
1279 except test_lists.TestListError as e:
1280 logging.exception('Invalid active test list: %s',
1281 self.options.test_list)
1282 startup_errors.append(e.message)
Jon Salz128b0932013-07-03 16:55:26 +08001283
Joel Kitching50a63ea2016-02-22 13:15:09 +08001284 # We may have failed loading the active test list.
1285 if self.test_list:
Joel Kitching50a63ea2016-02-22 13:15:09 +08001286 self.test_list.state_instance = self.state_instance
Jon Salz128b0932013-07-03 16:55:26 +08001287
Joel Kitching50a63ea2016-02-22 13:15:09 +08001288 # Prepare DUT link.
1289 if self.test_list.options.dut_options:
1290 logging.info('dut_options set by %s: %r', self.test_list.test_list_id,
1291 self.test_list.options.dut_options)
Hung-Te Linb6287242016-05-18 14:39:05 +08001292 device_utils.PrepareDUTLink(**self.test_list.options.dut_options)
Wei-Han Chene8a025f2016-01-14 16:42:02 +08001293
Joel Kitching50a63ea2016-02-22 13:15:09 +08001294 # Show all startup errors.
1295 if startup_errors:
1296 self.state_instance.set_shared_data(
1297 'startup_error', '\n\n'.join(startup_errors))
1298
1299 # Only return False if failed to load the active test list.
1300 return bool(self.test_list)
Jon Salz128b0932013-07-03 16:55:26 +08001301
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001302 def init_hooks(self):
1303 """Initializes hooks.
1304
1305 Must run after self.test_list ready.
1306 """
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001307 module, cls = self.test_list.options.hooks_class.rsplit('.', 1)
1308 self.hooks = getattr(__import__(module, fromlist=[cls]), cls)()
1309 assert isinstance(self.hooks, factory.Hooks), (
Ricky Liang45c73e72015-01-15 15:00:30 +08001310 'hooks should be of type Hooks but is %r' % type(self.hooks))
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001311 self.hooks.test_list = self.test_list
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001312 self.hooks.OnCreatedTestList()
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001313
Vic Yanga3cecf82014-12-26 00:44:21 -08001314 def init_ui(self):
1315 """Initialize UI."""
1316 self._ui_initialized = True
1317 if self.options.ui == 'chrome':
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001318 if self.options.monolithic:
Hung-Te Lin7bd55312014-12-30 16:43:36 +08001319 self.env.launch_chrome()
1320 else:
1321 # The presenter is responsible for launching Chrome. Let's just
1322 # wait here.
1323 self.env.controller_ready_for_ui()
Vic Yanga3cecf82014-12-26 00:44:21 -08001324 logging.info('Waiting for a web socket connection')
1325 self.web_socket_manager.wait()
1326
1327 # Wait for the test widget size to be set; this is done in
1328 # an asynchronous RPC so there is a small chance that the
1329 # web socket might be opened first.
1330 for _ in range(100): # 10 s
1331 try:
1332 if self.state_instance.get_shared_data('test_widget_size'):
1333 break
1334 except KeyError:
1335 pass # Retry
1336 time.sleep(0.1) # 100 ms
1337 else:
1338 logging.warn('Never received test_widget_size from UI')
1339
Jon Salz0697cbf2012-07-04 15:14:04 +08001340 def init(self, args=None, env=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001341 """Initializes Goofy.
Jon Salz0697cbf2012-07-04 15:14:04 +08001342
1343 Args:
1344 args: A list of command-line arguments. Uses sys.argv if
1345 args is None.
1346 env: An Environment instance to use (or None to choose
1347 FakeChrootEnvironment or DUTEnvironment as appropriate).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001348 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001349 parser = OptionParser()
1350 parser.add_option('-v', '--verbose', dest='verbose',
Jon Salz8fa8e832012-07-13 19:04:09 +08001351 action='store_true',
1352 help='Enable debug logging')
Jon Salz0697cbf2012-07-04 15:14:04 +08001353 parser.add_option('--print_test_list', dest='print_test_list',
Wei-Han Chen84fee7c2016-08-26 21:56:25 +08001354 metavar='TEST_LIST_ID',
1355 help='Print the content of TEST_LIST_ID and exit')
Jon Salz0697cbf2012-07-04 15:14:04 +08001356 parser.add_option('--restart', dest='restart',
Jon Salz8fa8e832012-07-13 19:04:09 +08001357 action='store_true',
1358 help='Clear all test state')
Jon Salz0697cbf2012-07-04 15:14:04 +08001359 parser.add_option('--ui', dest='ui', type='choice',
Jon Salz7b5482e2014-08-04 17:48:41 +08001360 choices=['none', 'chrome'],
Jon Salz2f881df2013-02-01 17:00:35 +08001361 default='chrome',
Jon Salz8fa8e832012-07-13 19:04:09 +08001362 help='UI to use')
Jon Salz0697cbf2012-07-04 15:14:04 +08001363 parser.add_option('--ui_scale_factor', dest='ui_scale_factor',
Jon Salz8fa8e832012-07-13 19:04:09 +08001364 type='int', default=1,
1365 help=('Factor by which to scale UI '
1366 '(Chrome UI only)'))
Jon Salz0697cbf2012-07-04 15:14:04 +08001367 parser.add_option('--test_list', dest='test_list',
Wei-Han Chen84fee7c2016-08-26 21:56:25 +08001368 metavar='TEST_LIST_ID',
1369 help='Use test list whose id is TEST_LIST_ID')
Jon Salzc79a9982012-08-30 04:42:01 +08001370 parser.add_option('--dummy_shopfloor', action='store_true',
1371 help='Use a dummy shopfloor server')
Hung-Te Lincc41d2a2014-10-29 13:35:20 +08001372 parser.add_option('--dummy_connection_manager', action='store_true',
1373 help='Use a dummy connection manager')
Ricky Liang6fe218c2013-12-27 15:17:17 +08001374 parser.add_option('--automation-mode',
1375 choices=[m.lower() for m in AutomationMode],
Ricky Liang45c73e72015-01-15 15:00:30 +08001376 default='none', help='Factory test automation mode.')
Ricky Liang117484a2014-04-14 11:14:41 +08001377 parser.add_option('--no-auto-run-on-start', dest='auto_run_on_start',
1378 action='store_false', default=True,
1379 help=('do not automatically run the test list on goofy '
1380 'start; this is only valid when factory test '
1381 'automation is enabled'))
Chun-Ta Lina8dd3172014-11-26 16:15:13 +08001382 parser.add_option('--handshake_timeout', dest='handshake_timeout',
1383 type='float', default=0.3,
1384 help=('RPC timeout when doing handshake between device '
1385 'and presenter.'))
Vic Yang7d693c42014-09-14 09:52:39 +08001386 parser.add_option('--standalone', dest='standalone',
1387 action='store_true', default=False,
1388 help=('Assume the presenter is running on the same '
1389 'machines.'))
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001390 parser.add_option('--monolithic', dest='monolithic',
1391 action='store_true', default=False,
1392 help='Run in monolithic mode (without presenter)')
Jon Salz0697cbf2012-07-04 15:14:04 +08001393 (self.options, self.args) = parser.parse_args(args)
1394
Hung-Te Lina846f602014-07-04 20:32:22 +08001395 signal.signal(signal.SIGINT, self.handle_sigint)
1396 # TODO(hungte) SIGTERM does not work properly without Telemetry and should
1397 # be fixed.
Hung-Te Lina846f602014-07-04 20:32:22 +08001398
Jon Salz46b89562012-07-05 11:49:22 +08001399 # Make sure factory directories exist.
Joel Kitching625ff0f2016-05-16 14:59:40 -07001400 paths.GetLogRoot()
1401 paths.GetStateRoot()
1402 paths.GetTestDataRoot()
Jon Salz46b89562012-07-05 11:49:22 +08001403
Jon Salz0697cbf2012-07-04 15:14:04 +08001404 global _inited_logging # pylint: disable=W0603
1405 if not _inited_logging:
1406 factory.init_logging('goofy', verbose=self.options.verbose)
1407 _inited_logging = True
Jon Salz8fa8e832012-07-13 19:04:09 +08001408
Jon Salz0f996602012-10-03 15:26:48 +08001409 if self.options.print_test_list:
Wei-Han Chen84fee7c2016-08-26 21:56:25 +08001410 test_list = test_lists.BuildTestList(self.options.print_test_list)
1411 print(test_list.__repr__(recursive=True))
Jon Salz0f996602012-10-03 15:26:48 +08001412 sys.exit(0)
1413
Jon Salzee85d522012-07-17 14:34:46 +08001414 event_log.IncrementBootSequence()
Chun-Ta Lin53cbbd52016-06-08 21:42:19 +08001415 testlog_goofy.IncrementInitCount()
1416
Jon Salzd15bbcf2013-05-21 17:33:57 +08001417 # Don't defer logging the initial event, so we can make sure
1418 # that device_id, reimage_id, etc. are all set up.
1419 self.event_log = EventLog('goofy', defer=False)
Chun-Ta Lin53cbbd52016-06-08 21:42:19 +08001420 self.testlog = testlog.Testlog(
1421 log_root=paths.GetLogRoot(), uuid=self.uuid)
1422 # Direct the logging calls to testlog as well.
1423 testlog.CapturePythonLogging(
1424 callback=self.testlog.primary_json.Log,
1425 level=logging.getLogger().getEffectiveLevel())
Jon Salz0697cbf2012-07-04 15:14:04 +08001426
Jon Salz0697cbf2012-07-04 15:14:04 +08001427 if env:
1428 self.env = env
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001429 elif sys_utils.InChroot():
Jon Salz0697cbf2012-07-04 15:14:04 +08001430 self.env = test_environment.FakeChrootEnvironment()
1431 logging.warn(
Ricky Liang45c73e72015-01-15 15:00:30 +08001432 'Using chroot environment: will not actually run autotests')
Hung-Te Lina846f602014-07-04 20:32:22 +08001433 elif self.options.ui == 'chrome':
Ricky Liang09d66d82014-09-25 11:20:54 +08001434 self.env = test_environment.DUTEnvironment()
Jon Salz0697cbf2012-07-04 15:14:04 +08001435 self.env.goofy = self
Vic Yanga4931152014-08-11 16:36:24 -07001436 # web_socket_manager will be initialized later
1437 # pylint: disable=W0108
1438 self.env.has_sockets = lambda: self.web_socket_manager.has_sockets()
Jon Salz0697cbf2012-07-04 15:14:04 +08001439
1440 if self.options.restart:
1441 state.clear_state()
1442
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001443 if self.options.ui_scale_factor != 1 and sys_utils.InQEMU():
Jon Salz0697cbf2012-07-04 15:14:04 +08001444 logging.warn(
Ricky Liang45c73e72015-01-15 15:00:30 +08001445 'In QEMU; ignoring ui_scale_factor argument')
Jon Salz0697cbf2012-07-04 15:14:04 +08001446 self.options.ui_scale_factor = 1
1447
1448 logging.info('Started')
1449
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001450 if not self.options.monolithic:
Hung-Te Lin7bd55312014-12-30 16:43:36 +08001451 self.link_manager = PresenterLinkManager(
1452 check_interval=1,
1453 handshake_timeout=self.options.handshake_timeout,
1454 standalone=self.options.standalone)
Peter Ammon1e1ec572014-06-26 17:56:32 -07001455
Jon Salz0697cbf2012-07-04 15:14:04 +08001456 self.start_state_server()
1457 self.state_instance.set_shared_data('hwid_cfg', get_hwid_cfg())
1458 self.state_instance.set_shared_data('ui_scale_factor',
Ricky Liang09216dc2013-02-22 17:26:45 +08001459 self.options.ui_scale_factor)
Jon Salz0697cbf2012-07-04 15:14:04 +08001460 self.last_shutdown_time = (
Ricky Liang45c73e72015-01-15 15:00:30 +08001461 self.state_instance.get_shared_data('shutdown_time', optional=True))
Jon Salz0697cbf2012-07-04 15:14:04 +08001462 self.state_instance.del_shared_data('shutdown_time', optional=True)
Jon Salzb19ea072013-02-07 16:35:00 +08001463 self.state_instance.del_shared_data('startup_error', optional=True)
Jon Salz0697cbf2012-07-04 15:14:04 +08001464
Ricky Liang6fe218c2013-12-27 15:17:17 +08001465 self.options.automation_mode = ParseAutomationMode(
1466 self.options.automation_mode)
1467 self.state_instance.set_shared_data('automation_mode',
1468 self.options.automation_mode)
1469 self.state_instance.set_shared_data(
1470 'automation_mode_prompt',
1471 AutomationModePrompt[self.options.automation_mode])
1472
Joel Kitching50a63ea2016-02-22 13:15:09 +08001473 success = False
1474 exc_info = None
Jon Salz128b0932013-07-03 16:55:26 +08001475 try:
Joel Kitching50a63ea2016-02-22 13:15:09 +08001476 success = self.InitTestLists()
Jon Salz128b0932013-07-03 16:55:26 +08001477 except: # pylint: disable=W0702
Joel Kitching50a63ea2016-02-22 13:15:09 +08001478 exc_info = sys.exc_info()
1479
1480 if not success:
1481 if exc_info:
1482 logging.exception('Unable to initialize test lists')
1483 self.state_instance.set_shared_data(
1484 'startup_error',
1485 'Unable to initialize test lists\n%s' % (
1486 traceback.format_exc()))
Jon Salzb19ea072013-02-07 16:35:00 +08001487 if self.options.ui == 'chrome':
1488 # Create an empty test list with default options so that the rest of
1489 # startup can proceed.
1490 self.test_list = factory.FactoryTestList(
1491 [], self.state_instance, factory.Options())
1492 else:
1493 # Bail with an error; no point in starting up.
1494 sys.exit('No valid test list; exiting.')
1495
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001496 self.init_hooks()
1497
Jon Salz822838b2013-03-25 17:32:33 +08001498 if self.test_list.options.clear_state_on_start:
1499 self.state_instance.clear_test_state()
1500
Jon Salz670ce062014-05-16 15:53:50 +08001501 # If the phase is invalid, this will raise a ValueError.
1502 phase.SetPersistentPhase(self.test_list.options.phase)
1503
Dean Liao85ca86f2014-11-03 12:28:08 +08001504 # For netboot firmware, mainfw_type should be 'netboot'.
Hung-Te Line594e5d2015-12-16 02:36:05 +08001505 if (self.dut.info.mainfw_type != 'nonchrome' and
1506 self.dut.info.firmware_version is None):
Ricky Liang45c73e72015-01-15 15:00:30 +08001507 self.state_instance.set_shared_data(
1508 'startup_error',
Vic Yang9bd4f772013-06-04 17:34:00 +08001509 'Netboot firmware detected\n'
1510 'Connect Ethernet and reboot to re-image.\n'
1511 u'侦测到网路开机固件\n'
1512 u'请连接乙太网并重启')
1513
Jon Salz0697cbf2012-07-04 15:14:04 +08001514 if not self.state_instance.has_shared_data('ui_lang'):
1515 self.state_instance.set_shared_data('ui_lang',
Ricky Liang45c73e72015-01-15 15:00:30 +08001516 self.test_list.options.ui_lang)
Jon Salz0697cbf2012-07-04 15:14:04 +08001517 self.state_instance.set_shared_data(
Ricky Liang45c73e72015-01-15 15:00:30 +08001518 'test_list_options',
1519 self.test_list.options.__dict__)
Jon Salz0697cbf2012-07-04 15:14:04 +08001520 self.state_instance.test_list = self.test_list
1521
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001522 self.check_log_rotation()
Jon Salz83ef34b2012-11-01 19:46:35 +08001523
Jon Salz23926422012-09-01 03:38:13 +08001524 if self.options.dummy_shopfloor:
Ricky Liang45c73e72015-01-15 15:00:30 +08001525 os.environ[shopfloor.SHOPFLOOR_SERVER_ENV_VAR_NAME] = (
1526 'http://%s:%d/' %
Joel Kitchingb85ed7f2014-10-08 18:24:39 +08001527 (net_utils.LOCALHOST, shopfloor.DEFAULT_SERVER_PORT))
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001528 self.dummy_shopfloor = process_utils.Spawn(
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +08001529 [os.path.join(paths.FACTORY_PATH, 'bin', 'shopfloor_server'),
Jon Salz23926422012-09-01 03:38:13 +08001530 '--dummy'])
1531 elif self.test_list.options.shopfloor_server_url:
1532 shopfloor.set_server_url(self.test_list.options.shopfloor_server_url)
Jon Salz2bf2f6b2013-03-28 18:49:26 +08001533 shopfloor.set_enabled(True)
Jon Salz23926422012-09-01 03:38:13 +08001534
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001535 if self.test_list.options.time_sanitizer and not sys_utils.InChroot():
Jon Salz8fa8e832012-07-13 19:04:09 +08001536 self.time_sanitizer = time_sanitizer.TimeSanitizer(
Ricky Liang45c73e72015-01-15 15:00:30 +08001537 base_time=time_sanitizer.GetBaseTimeFromFile(
1538 # lsb-factory is written by the factory install shim during
1539 # installation, so it should have a good time obtained from
1540 # the mini-Omaha server. If it's not available, we'll use
1541 # /etc/lsb-factory (which will be much older, but reasonably
1542 # sane) and rely on a shopfloor sync to set a more accurate
1543 # time.
1544 '/usr/local/etc/lsb-factory',
1545 '/etc/lsb-release'))
Jon Salz8fa8e832012-07-13 19:04:09 +08001546 self.time_sanitizer.RunOnce()
1547
Vic Yangd8990da2013-06-27 16:57:43 +08001548 if self.test_list.options.check_cpu_usage_period_secs:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001549 self.cpu_usage_watcher = process_utils.Spawn(
Ricky Liang45c73e72015-01-15 15:00:30 +08001550 ['py/tools/cpu_usage_monitor.py', '-p',
1551 str(self.test_list.options.check_cpu_usage_period_secs)],
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +08001552 cwd=paths.FACTORY_PATH)
Vic Yangd8990da2013-06-27 16:57:43 +08001553
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001554 # Enable thermal monitor
1555 if self.test_list.options.thermal_monitor_period_secs > 0:
Hung-Te Lin23cb7612016-01-19 19:19:32 +08001556 self.thermal_watcher = process_utils.Spawn(
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001557 ['py/tools/thermal_monitor.py',
1558 '-p', str(self.test_list.options.thermal_monitor_period_secs),
1559 '-d', str(self.test_list.options.thermal_monitor_delta)],
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +08001560 cwd=paths.FACTORY_PATH)
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001561
Jon Salz0697cbf2012-07-04 15:14:04 +08001562 self.init_states()
1563 self.start_event_server()
Wei-Ning Huang38b75f02015-02-25 18:25:14 +08001564 self.start_terminal_server()
Hung-Te Lincc41d2a2014-10-29 13:35:20 +08001565
1566 if self.options.dummy_connection_manager:
1567 # Override network manager creation to dummy implmenetation.
1568 logging.info('Using dummy network manager (--dummy_connection_manager).')
1569 self.connection_manager = connection_manager.DummyConnectionManager()
1570 else:
1571 self.connection_manager = self.env.create_connection_manager(
1572 self.test_list.options.wlans,
Mao Huang4340c632015-04-14 14:35:22 +08001573 self.test_list.options.scan_wifi_period_secs,
1574 self.test_list.options.override_blacklisted_network_devices)
Hung-Te Lincc41d2a2014-10-29 13:35:20 +08001575
Jon Salz0697cbf2012-07-04 15:14:04 +08001576 # Note that we create a log watcher even if
1577 # sync_event_log_period_secs isn't set (no background
1578 # syncing), since we may use it to flush event logs as well.
1579 self.log_watcher = EventLogWatcher(
Ricky Liang45c73e72015-01-15 15:00:30 +08001580 self.test_list.options.sync_event_log_period_secs,
1581 event_log_db_file=None,
1582 handle_event_logs_callback=self.handle_event_logs)
Jon Salz0697cbf2012-07-04 15:14:04 +08001583 if self.test_list.options.sync_event_log_period_secs:
1584 self.log_watcher.StartWatchThread()
1585
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001586 # Creates a system log manager to scan logs periocially.
1587 # A scan includes clearing logs and optionally syncing logs if
1588 # enable_syng_log is True. We kick it to sync logs.
1589 self.system_log_manager = SystemLogManager(
Ricky Liang45c73e72015-01-15 15:00:30 +08001590 sync_log_paths=self.test_list.options.sync_log_paths,
1591 sync_log_period_secs=self.test_list.options.sync_log_period_secs,
1592 scan_log_period_secs=self.test_list.options.scan_log_period_secs,
1593 clear_log_paths=self.test_list.options.clear_log_paths,
1594 clear_log_excluded_paths=self.test_list.options.clear_log_excluded_paths)
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001595 self.system_log_manager.Start()
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +08001596
Jon Salz0697cbf2012-07-04 15:14:04 +08001597 self.update_system_info()
1598
Vic Yang4953fc12012-07-26 16:19:53 +08001599 assert ((self.test_list.options.min_charge_pct is None) ==
1600 (self.test_list.options.max_charge_pct is None))
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001601 if sys_utils.InChroot():
Vic Yange83d9a12013-04-19 20:00:20 +08001602 logging.info('In chroot, ignoring charge manager and charge state')
Ricky Liangc392a1c2014-06-20 18:24:59 +08001603 elif (self.test_list.options.enable_charge_manager and
1604 self.test_list.options.min_charge_pct is not None):
Vic Yang4953fc12012-07-26 16:19:53 +08001605 self.charge_manager = ChargeManager(self.test_list.options.min_charge_pct,
1606 self.test_list.options.max_charge_pct)
Hung-Te Linc17b3d82015-12-15 15:26:08 +08001607 self.dut.status.Overrides('charge_manager', self.charge_manager)
Cheng-Yi Chiangd8186952013-04-04 23:41:14 +08001608 else:
1609 # Goofy should set charger state to charge if charge_manager is disabled.
Dean Liao88b93192014-10-23 19:37:41 +08001610 self.charge()
Vic Yang4953fc12012-07-26 16:19:53 +08001611
Vic Yang6cee2472014-10-22 17:18:52 -07001612 if CoreDumpManager.CoreDumpEnabled():
1613 self.core_dump_manager = CoreDumpManager(
1614 self.test_list.options.core_dump_watchlist)
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001615
Jon Salz0697cbf2012-07-04 15:14:04 +08001616 os.environ['CROS_FACTORY'] = '1'
1617 os.environ['CROS_DISABLE_SITE_SYSINFO'] = '1'
1618
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001619 if not sys_utils.InChroot() and self.test_list.options.use_cpufreq_manager:
Ricky Liangecddbd42014-07-24 11:32:10 +08001620 logging.info('Enabling CPU frequency manager')
Jon Salzddf0d052013-06-18 12:52:44 +08001621 self.cpufreq_manager = CpufreqManager(event_log=self.event_log)
Jon Salzce6a7f82013-06-10 18:22:54 +08001622
Justin Chuang31b02432013-06-27 15:16:51 +08001623 # Startup hooks may want to skip some tests.
1624 self.update_skipped_tests()
Jon Salz416f9cc2013-05-10 18:32:50 +08001625
Jon Salze12c2b32013-06-25 16:24:34 +08001626 self.find_kcrashes()
1627
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001628 # Should not move earlier.
1629 self.hooks.OnStartup()
1630
Ricky Liang36512a32014-07-25 11:47:04 +08001631 # Only after this point the Goofy backend is ready for UI connection.
1632 self.ready_for_ui_connection = True
1633
Ricky Liang650f6bf2012-09-28 13:22:54 +08001634 # Create download path for autotest beforehand or autotests run at
1635 # the same time might fail due to race condition.
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001636 if not sys_utils.InChroot():
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001637 file_utils.TryMakeDirs(os.path.join('/usr/local/autotest', 'tests',
1638 'download'))
Ricky Liang650f6bf2012-09-28 13:22:54 +08001639
Jon Salz0697cbf2012-07-04 15:14:04 +08001640 def state_change_callback(test, test_state):
1641 self.event_client.post_event(
Ricky Liang4bff3e32014-02-20 18:46:11 +08001642 Event(Event.Type.STATE_CHANGE, path=test.path, state=test_state))
Jon Salz0697cbf2012-07-04 15:14:04 +08001643 self.test_list.state_change_callback = state_change_callback
Jon Salz73e0fd02012-04-04 11:46:38 +08001644
Vic Yange2c76a82014-10-30 12:48:19 -07001645 self.autotest_prespawner = prespawner.AutotestPrespawner()
1646 self.autotest_prespawner.start()
1647
1648 self.pytest_prespawner = prespawner.PytestPrespawner()
1649 self.pytest_prespawner.start()
Jon Salza6711d72012-07-18 14:33:03 +08001650
Ricky Liang48e47f92014-02-26 19:31:51 +08001651 tests_after_shutdown = self.state_instance.get_shared_data(
1652 'tests_after_shutdown', optional=True)
Jon Salz57717ca2012-04-04 16:47:25 +08001653
Jon Salz5c344f62012-07-13 14:31:16 +08001654 force_auto_run = (tests_after_shutdown == FORCE_AUTO_RUN)
1655 if not force_auto_run and tests_after_shutdown is not None:
Ricky Liang48e47f92014-02-26 19:31:51 +08001656 logging.info('Resuming tests after shutdown: %s', tests_after_shutdown)
Jon Salz0697cbf2012-07-04 15:14:04 +08001657 self.tests_to_run.extend(
Ricky Liang4bff3e32014-02-20 18:46:11 +08001658 self.test_list.lookup_path(t) for t in tests_after_shutdown)
Peter Ammon1e1ec572014-06-26 17:56:32 -07001659 self.run_enqueue(self.run_next_test)
Jon Salz0697cbf2012-07-04 15:14:04 +08001660 else:
Jon Salz5c344f62012-07-13 14:31:16 +08001661 if force_auto_run or self.test_list.options.auto_run_on_start:
Ricky Liang117484a2014-04-14 11:14:41 +08001662 # If automation mode is enabled, allow suppress auto_run_on_start.
1663 if (self.options.automation_mode == 'NONE' or
1664 self.options.auto_run_on_start):
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +08001665 status_filter = [TestState.UNTESTED]
1666 if self.test_list.options.retry_failed_on_start:
1667 status_filter.append(TestState.FAILED)
1668 self.run_enqueue(lambda: self.run_tests(self.test_list, status_filter))
Jon Salz5c344f62012-07-13 14:31:16 +08001669 self.state_instance.set_shared_data('tests_after_shutdown', None)
Ricky Liang4bff3e32014-02-20 18:46:11 +08001670 self.restore_active_run_state()
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001671
Hung-Te Lin410f70a2015-12-15 14:53:42 +08001672 self.dut.hooks.OnTestStart()
Vic Yang08505c72015-01-06 17:01:53 -08001673
Dean Liao592e4d52013-01-10 20:06:39 +08001674 self.may_disable_cros_shortcut_keys()
1675
1676 def may_disable_cros_shortcut_keys(self):
1677 test_options = self.test_list.options
1678 if test_options.disable_cros_shortcut_keys:
1679 logging.info('Filter ChromeOS shortcut keys.')
1680 self.key_filter = KeyFilter(
1681 unmap_caps_lock=test_options.disable_caps_lock,
1682 caps_lock_keycode=test_options.caps_lock_keycode)
1683 self.key_filter.Start()
1684
Jon Salz0e6532d2012-10-25 16:30:11 +08001685 def _should_sync_time(self, foreground=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001686 """Returns True if we should attempt syncing time with shopfloor.
Jon Salz0e6532d2012-10-25 16:30:11 +08001687
1688 Args:
1689 foreground: If True, synchronizes even if background syncing
1690 is disabled (e.g., in explicit sync requests from the
1691 SyncShopfloor test).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001692 """
Jon Salz0e6532d2012-10-25 16:30:11 +08001693 return ((foreground or
1694 self.test_list.options.sync_time_period_secs) and
Jon Salz54882d02012-08-31 01:57:54 +08001695 self.time_sanitizer and
1696 (not self.time_synced) and
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001697 (not sys_utils.InChroot()))
Jon Salz54882d02012-08-31 01:57:54 +08001698
Jon Salz0e6532d2012-10-25 16:30:11 +08001699 def sync_time_with_shopfloor_server(self, foreground=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001700 """Syncs time with shopfloor server, if not yet synced.
Jon Salz54882d02012-08-31 01:57:54 +08001701
Jon Salz0e6532d2012-10-25 16:30:11 +08001702 Args:
1703 foreground: If True, synchronizes even if background syncing
1704 is disabled (e.g., in explicit sync requests from the
1705 SyncShopfloor test).
1706
Jon Salz54882d02012-08-31 01:57:54 +08001707 Returns:
1708 False if no time sanitizer is available, or True if this sync (or a
1709 previous sync) succeeded.
1710
1711 Raises:
1712 Exception if unable to contact the shopfloor server.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001713 """
Jon Salz0e6532d2012-10-25 16:30:11 +08001714 if self._should_sync_time(foreground):
Jon Salz54882d02012-08-31 01:57:54 +08001715 self.time_sanitizer.SyncWithShopfloor()
1716 self.time_synced = True
1717 return self.time_synced
1718
Jon Salzb92c5112012-09-21 15:40:11 +08001719 def log_disk_space_stats(self):
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001720 if (sys_utils.InChroot() or
Jon Salz18e0e022013-06-11 17:13:39 +08001721 not self.test_list.options.log_disk_space_period_secs):
Jon Salzb92c5112012-09-21 15:40:11 +08001722 return
1723
1724 now = time.time()
1725 if (self.last_log_disk_space_time and
1726 now - self.last_log_disk_space_time <
1727 self.test_list.options.log_disk_space_period_secs):
1728 return
1729 self.last_log_disk_space_time = now
1730
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001731 # Upload event if stateful partition usage is above threshold.
1732 # Stateful partition is mounted on /usr/local, while
1733 # encrypted stateful partition is mounted on /var.
1734 # If there are too much logs in the factory process,
1735 # these two partitions might get full.
Jon Salzb92c5112012-09-21 15:40:11 +08001736 try:
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001737 vfs_infos = disk_space.GetAllVFSInfo()
1738 stateful_info, encrypted_info = None, None
1739 for vfs_info in vfs_infos.values():
1740 if '/usr/local' in vfs_info.mount_points:
1741 stateful_info = vfs_info
1742 if '/var' in vfs_info.mount_points:
1743 encrypted_info = vfs_info
1744
1745 stateful = disk_space.GetPartitionUsage(stateful_info)
1746 encrypted = disk_space.GetPartitionUsage(encrypted_info)
1747
Ricky Liang45c73e72015-01-15 15:00:30 +08001748 above_threshold = (
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001749 self.test_list.options.stateful_usage_threshold and
1750 max(stateful.bytes_used_pct,
1751 stateful.inodes_used_pct,
1752 encrypted.bytes_used_pct,
1753 encrypted.inodes_used_pct) >
Ricky Liang45c73e72015-01-15 15:00:30 +08001754 self.test_list.options.stateful_usage_threshold)
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001755
1756 if above_threshold:
1757 self.event_log.Log('stateful_partition_usage',
Ricky Liang45c73e72015-01-15 15:00:30 +08001758 partitions={
1759 'stateful': {
1760 'bytes_used_pct': FloatDigit(stateful.bytes_used_pct, 2),
1761 'inodes_used_pct': FloatDigit(stateful.inodes_used_pct, 2)},
1762 'encrypted_stateful': {
1763 'bytes_used_pct': FloatDigit(encrypted.bytes_used_pct, 2),
1764 'inodes_used_pct': FloatDigit(encrypted.inodes_used_pct, 2)}
1765 })
Cheng-Yi Chiang1b722322015-03-16 20:07:03 +08001766 self.log_watcher.KickWatchThread()
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001767 if (not sys_utils.InChroot() and
Cheng-Yi Chiang00798e72013-06-20 18:16:39 +08001768 self.test_list.options.stateful_usage_above_threshold_action):
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001769 process_utils.Spawn(
1770 self.test_list.options.stateful_usage_above_threshold_action,
1771 call=True)
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001772
1773 message = disk_space.FormatSpaceUsedAll(vfs_infos)
Jon Salz3c493bb2013-02-07 17:24:58 +08001774 if message != self.last_log_disk_space_message:
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001775 if above_threshold:
1776 logging.warning(message)
1777 else:
1778 logging.info(message)
Jon Salz3c493bb2013-02-07 17:24:58 +08001779 self.last_log_disk_space_message = message
Jon Salzb92c5112012-09-21 15:40:11 +08001780 except: # pylint: disable=W0702
1781 logging.exception('Unable to get disk space used')
1782
Justin Chuang83813982013-05-13 01:26:32 +08001783 def check_battery(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001784 """Checks the current battery status.
Justin Chuang83813982013-05-13 01:26:32 +08001785
1786 Logs current battery charging level and status to log. If the battery level
1787 is lower below warning_low_battery_pct, send warning event to shopfloor.
1788 If the battery level is lower below critical_low_battery_pct, flush disks.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001789 """
Justin Chuang83813982013-05-13 01:26:32 +08001790 if not self.test_list.options.check_battery_period_secs:
1791 return
1792
1793 now = time.time()
1794 if (self.last_check_battery_time and
1795 now - self.last_check_battery_time <
1796 self.test_list.options.check_battery_period_secs):
1797 return
1798 self.last_check_battery_time = now
1799
1800 message = ''
1801 log_level = logging.INFO
1802 try:
Hung-Te Lin6a72c642015-12-13 22:09:09 +08001803 power = self.dut.power
Justin Chuang83813982013-05-13 01:26:32 +08001804 if not power.CheckBatteryPresent():
1805 message = 'Battery is not present'
1806 else:
1807 ac_present = power.CheckACPresent()
1808 charge_pct = power.GetChargePct(get_float=True)
1809 message = ('Current battery level %.1f%%, AC charger is %s' %
1810 (charge_pct, 'connected' if ac_present else 'disconnected'))
1811
1812 if charge_pct > self.test_list.options.critical_low_battery_pct:
1813 critical_low_battery = False
1814 else:
1815 critical_low_battery = True
1816 # Only sync disks when battery level is still above minimum
1817 # value. This can be used for offline analysis when shopfloor cannot
1818 # be connected.
1819 if charge_pct > MIN_BATTERY_LEVEL_FOR_DISK_SYNC:
1820 logging.warning('disk syncing for critical low battery situation')
1821 os.system('sync; sync; sync')
1822 else:
1823 logging.warning('disk syncing is cancelled '
1824 'because battery level is lower than %.1f',
1825 MIN_BATTERY_LEVEL_FOR_DISK_SYNC)
1826
1827 # Notify shopfloor server
1828 if (critical_low_battery or
1829 (not ac_present and
1830 charge_pct <= self.test_list.options.warning_low_battery_pct)):
1831 log_level = logging.WARNING
1832
1833 self.event_log.Log('low_battery',
1834 battery_level=charge_pct,
1835 charger_connected=ac_present,
1836 critical=critical_low_battery)
1837 self.log_watcher.KickWatchThread()
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001838 if self.test_list.options.enable_sync_log:
1839 self.system_log_manager.KickToSync()
Ricky Liang45c73e72015-01-15 15:00:30 +08001840 except: # pylint: disable=W0702
Justin Chuang83813982013-05-13 01:26:32 +08001841 logging.exception('Unable to check battery or notify shopfloor')
1842 finally:
1843 if message != self.last_check_battery_message:
1844 logging.log(log_level, message)
1845 self.last_check_battery_message = message
1846
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001847 def check_core_dump(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001848 """Checks if there is any core dumped file.
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001849
1850 Removes unwanted core dump files immediately.
1851 Syncs those files matching watch list to server with a delay between
1852 each sync. After the files have been synced to server, deletes the files.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001853 """
Vic Yang6cee2472014-10-22 17:18:52 -07001854 if not self.core_dump_manager:
1855 return
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001856 core_dump_files = self.core_dump_manager.ScanFiles()
1857 if core_dump_files:
1858 now = time.time()
1859 if (self.last_kick_sync_time and now - self.last_kick_sync_time <
1860 self.test_list.options.kick_sync_min_interval_secs):
1861 return
1862 self.last_kick_sync_time = now
1863
1864 # Sends event to server
1865 self.event_log.Log('core_dumped', files=core_dump_files)
1866 self.log_watcher.KickWatchThread()
1867
1868 # Syncs files to server
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001869 if self.test_list.options.enable_sync_log:
1870 self.system_log_manager.KickToSync(
Cheng-Yi Chiangd3516a32013-07-17 15:30:47 +08001871 core_dump_files, self.core_dump_manager.ClearFiles)
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001872
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001873 def check_log_rotation(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001874 """Checks log rotation file presence/absence according to test_list option.
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001875
1876 Touch /var/lib/cleanup_logs_paused if test_list.options.disable_log_rotation
1877 is True, delete it otherwise. This must be done in idle loop because
1878 autotest client will touch /var/lib/cleanup_logs_paused each time it runs
1879 an autotest.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001880 """
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001881 if sys_utils.InChroot():
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001882 return
1883 try:
1884 if self.test_list.options.disable_log_rotation:
1885 open(CLEANUP_LOGS_PAUSED, 'w').close()
1886 else:
1887 file_utils.TryUnlink(CLEANUP_LOGS_PAUSED)
1888 except: # pylint: disable=W0702
1889 # Oh well. Logs an error (but no trace)
1890 logging.info(
1891 'Unable to %s %s: %s',
1892 'touch' if self.test_list.options.disable_log_rotation else 'delete',
Hung-Te Linf707b242016-01-08 23:11:42 +08001893 CLEANUP_LOGS_PAUSED, debug_utils.FormatExceptionOnly())
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001894
Jon Salz8fa8e832012-07-13 19:04:09 +08001895 def sync_time_in_background(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001896 """Writes out current time and tries to sync with shopfloor server."""
Jon Salzb22d1172012-08-06 10:38:57 +08001897 if not self.time_sanitizer:
1898 return
1899
1900 # Write out the current time.
1901 self.time_sanitizer.SaveTime()
1902
Jon Salz54882d02012-08-31 01:57:54 +08001903 if not self._should_sync_time():
Jon Salz8fa8e832012-07-13 19:04:09 +08001904 return
1905
1906 now = time.time()
1907 if self.last_sync_time and (
1908 now - self.last_sync_time <
1909 self.test_list.options.sync_time_period_secs):
1910 # Not yet time for another check.
1911 return
1912 self.last_sync_time = now
1913
1914 def target():
1915 try:
Jon Salz54882d02012-08-31 01:57:54 +08001916 self.sync_time_with_shopfloor_server()
Jon Salz8fa8e832012-07-13 19:04:09 +08001917 except: # pylint: disable=W0702
1918 # Oh well. Log an error (but no trace)
1919 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +08001920 'Unable to get time from shopfloor server: %s',
Hung-Te Linf707b242016-01-08 23:11:42 +08001921 debug_utils.FormatExceptionOnly())
Jon Salz8fa8e832012-07-13 19:04:09 +08001922
1923 thread = threading.Thread(target=target)
1924 thread.daemon = True
1925 thread.start()
1926
Peter Ammon1e1ec572014-06-26 17:56:32 -07001927 def perform_periodic_tasks(self):
1928 """Override of base method to perform periodic work.
Vic Yang4953fc12012-07-26 16:19:53 +08001929
Peter Ammon1e1ec572014-06-26 17:56:32 -07001930 This method must not raise exceptions.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001931 """
Peter Ammon1e1ec572014-06-26 17:56:32 -07001932 super(Goofy, self).perform_periodic_tasks()
Jon Salzb22d1172012-08-06 10:38:57 +08001933
Vic Yang311ddb82012-09-26 12:08:28 +08001934 self.check_exclusive()
cychiang21886742012-07-05 15:16:32 +08001935 self.check_for_updates()
Jon Salz8fa8e832012-07-13 19:04:09 +08001936 self.sync_time_in_background()
Jon Salzb92c5112012-09-21 15:40:11 +08001937 self.log_disk_space_stats()
Justin Chuang83813982013-05-13 01:26:32 +08001938 self.check_battery()
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001939 self.check_core_dump()
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001940 self.check_log_rotation()
Jon Salz57717ca2012-04-04 16:47:25 +08001941
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001942 def handle_event_logs(self, chunks, periodic=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001943 """Callback for event watcher.
Jon Salz258a40c2012-04-19 12:34:01 +08001944
Jon Salz0697cbf2012-07-04 15:14:04 +08001945 Attempts to upload the event logs to the shopfloor server.
Vic Yang93027612013-05-06 02:42:49 +08001946
1947 Args:
Jon Salzd15bbcf2013-05-21 17:33:57 +08001948 chunks: A list of Chunk objects.
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001949 periodic: This event log handling is periodic. Error messages
1950 will only be shown for the first time.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001951 """
Vic Yang93027612013-05-06 02:42:49 +08001952 first_exception = None
1953 exception_count = 0
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001954 # Suppress error messages for periodic event syncing except for the
1955 # first time. If event syncing is not periodic, always show the error
1956 # messages.
1957 quiet = self._suppress_event_log_error_messages if periodic else False
Vic Yang93027612013-05-06 02:42:49 +08001958
Jon Salzd15bbcf2013-05-21 17:33:57 +08001959 for chunk in chunks:
Vic Yang93027612013-05-06 02:42:49 +08001960 try:
Jon Salzcddb6402013-05-23 12:56:42 +08001961 description = 'event logs (%s)' % str(chunk)
Vic Yang93027612013-05-06 02:42:49 +08001962 start_time = time.time()
1963 shopfloor_client = shopfloor.get_instance(
Ricky Liang45c73e72015-01-15 15:00:30 +08001964 detect=True,
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001965 timeout=self.test_list.options.shopfloor_timeout_secs,
1966 quiet=quiet)
Ricky Liang45c73e72015-01-15 15:00:30 +08001967 shopfloor_client.UploadEvent(chunk.log_name + '.' +
Jon Salzd15bbcf2013-05-21 17:33:57 +08001968 event_log.GetReimageId(),
1969 Binary(chunk.chunk))
Vic Yang93027612013-05-06 02:42:49 +08001970 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +08001971 'Successfully synced %s in %.03f s',
1972 description, time.time() - start_time)
1973 except: # pylint: disable=W0702
Hung-Te Linf707b242016-01-08 23:11:42 +08001974 first_exception = (first_exception or
1975 (chunk.log_name + ': ' +
1976 debug_utils.FormatExceptionOnly()))
Vic Yang93027612013-05-06 02:42:49 +08001977 exception_count += 1
1978
1979 if exception_count:
1980 if exception_count == 1:
1981 msg = 'Log upload failed: %s' % first_exception
1982 else:
1983 msg = '%d log upload failed; first is: %s' % (
1984 exception_count, first_exception)
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001985 # For periodic event log syncing, only show the first error messages.
1986 if periodic:
1987 if not self._suppress_event_log_error_messages:
1988 self._suppress_event_log_error_messages = True
1989 logging.warning('Suppress periodic shopfloor error messages for '
1990 'event log syncing after the first one.')
1991 raise Exception(msg)
1992 # For event log syncing by request, show the error messages.
1993 else:
1994 raise Exception(msg)
Vic Yang93027612013-05-06 02:42:49 +08001995
Ricky Liang45c73e72015-01-15 15:00:30 +08001996 def run_tests_with_status(self, statuses_to_run, starting_at=None, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001997 """Runs all top-level tests with a particular status.
Jon Salz0405ab52012-03-16 15:26:52 +08001998
Jon Salz0697cbf2012-07-04 15:14:04 +08001999 All active tests, plus any tests to re-run, are reset.
Jon Salz57717ca2012-04-04 16:47:25 +08002000
Jon Salz0697cbf2012-07-04 15:14:04 +08002001 Args:
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002002 statuses_to_run: The particular status that caller wants to run.
Jon Salz0697cbf2012-07-04 15:14:04 +08002003 starting_at: If provided, only auto-runs tests beginning with
2004 this test.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002005 root: The root of tests to run. If not provided, it will be
2006 the root of all tests.
2007 """
Jon Salz0697cbf2012-07-04 15:14:04 +08002008 root = root or self.test_list
Jon Salz57717ca2012-04-04 16:47:25 +08002009
Jon Salz0697cbf2012-07-04 15:14:04 +08002010 if starting_at:
2011 # Make sure they passed a test, not a string.
2012 assert isinstance(starting_at, factory.FactoryTest)
Jon Salz0405ab52012-03-16 15:26:52 +08002013
Jon Salz0697cbf2012-07-04 15:14:04 +08002014 tests_to_reset = []
2015 tests_to_run = []
Jon Salz0405ab52012-03-16 15:26:52 +08002016
Jon Salz0697cbf2012-07-04 15:14:04 +08002017 found_starting_at = False
Jon Salz0405ab52012-03-16 15:26:52 +08002018
Jon Salz0697cbf2012-07-04 15:14:04 +08002019 for test in root.get_top_level_tests():
2020 if starting_at:
2021 if test == starting_at:
2022 # We've found starting_at; do auto-run on all
2023 # subsequent tests.
2024 found_starting_at = True
2025 if not found_starting_at:
2026 # Don't start this guy yet
2027 continue
Jon Salz0405ab52012-03-16 15:26:52 +08002028
Jon Salz0697cbf2012-07-04 15:14:04 +08002029 status = test.get_state().status
2030 if status == TestState.ACTIVE or status in statuses_to_run:
2031 # Reset the test (later; we will need to abort
2032 # all active tests first).
2033 tests_to_reset.append(test)
2034 if status in statuses_to_run:
2035 tests_to_run.append(test)
Jon Salz0405ab52012-03-16 15:26:52 +08002036
Jon Salz6dc031d2013-06-19 13:06:23 +08002037 self.abort_active_tests('Operator requested run/re-run of certain tests')
Jon Salz258a40c2012-04-19 12:34:01 +08002038
Jon Salz0697cbf2012-07-04 15:14:04 +08002039 # Reset all statuses of the tests to run (in case any tests were active;
2040 # we want them to be run again).
2041 for test_to_reset in tests_to_reset:
2042 for test in test_to_reset.walk():
2043 test.update_state(status=TestState.UNTESTED)
Jon Salz57717ca2012-04-04 16:47:25 +08002044
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +08002045 self.run_tests(tests_to_run, [TestState.UNTESTED])
Jon Salz0405ab52012-03-16 15:26:52 +08002046
Jon Salz0697cbf2012-07-04 15:14:04 +08002047 def restart_tests(self, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002048 """Restarts all tests."""
Jon Salz0697cbf2012-07-04 15:14:04 +08002049 root = root or self.test_list
Jon Salz0405ab52012-03-16 15:26:52 +08002050
Jon Salz6dc031d2013-06-19 13:06:23 +08002051 self.abort_active_tests('Operator requested restart of certain tests')
Jon Salz0697cbf2012-07-04 15:14:04 +08002052 for test in root.walk():
Ricky Liangfea4ac92014-08-21 11:55:59 +08002053 test.update_state(status=TestState.UNTESTED)
Jon Salz0697cbf2012-07-04 15:14:04 +08002054 self.run_tests(root)
Hung-Te Lin96632362012-03-20 21:14:18 +08002055
Jon Salz0697cbf2012-07-04 15:14:04 +08002056 def auto_run(self, starting_at=None, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002057 """"Auto-runs" tests that have not been run yet.
Hung-Te Lin96632362012-03-20 21:14:18 +08002058
Jon Salz0697cbf2012-07-04 15:14:04 +08002059 Args:
2060 starting_at: If provide, only auto-runs tests beginning with
2061 this test.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002062 root: If provided, the root of tests to run. If not provided, the root
2063 will be test_list (root of all tests).
2064 """
Jon Salz0697cbf2012-07-04 15:14:04 +08002065 root = root or self.test_list
2066 self.run_tests_with_status([TestState.UNTESTED, TestState.ACTIVE],
Ricky Liang45c73e72015-01-15 15:00:30 +08002067 starting_at=starting_at,
2068 root=root)
Jon Salz968e90b2012-03-18 16:12:43 +08002069
Jon Salz0697cbf2012-07-04 15:14:04 +08002070 def handle_switch_test(self, event):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002071 """Switches to a particular test.
Jon Salz0405ab52012-03-16 15:26:52 +08002072
Ricky Liang6fe218c2013-12-27 15:17:17 +08002073 Args:
2074 event: The SWITCH_TEST event.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002075 """
Jon Salz0697cbf2012-07-04 15:14:04 +08002076 test = self.test_list.lookup_path(event.path)
2077 if not test:
2078 logging.error('Unknown test %r', event.key)
2079 return
Jon Salz73e0fd02012-04-04 11:46:38 +08002080
Jon Salz0697cbf2012-07-04 15:14:04 +08002081 invoc = self.invocations.get(test)
2082 if invoc and test.backgroundable:
2083 # Already running: just bring to the front if it
2084 # has a UI.
2085 logging.info('Setting visible test to %s', test.path)
Jon Salz36fbbb52012-07-05 13:45:06 +08002086 self.set_visible_test(test)
Jon Salz0697cbf2012-07-04 15:14:04 +08002087 return
Jon Salz73e0fd02012-04-04 11:46:38 +08002088
Jon Salz6dc031d2013-06-19 13:06:23 +08002089 self.abort_active_tests('Operator requested abort (switch_test)')
Jon Salz0697cbf2012-07-04 15:14:04 +08002090 for t in test.walk():
2091 t.update_state(status=TestState.UNTESTED)
Jon Salz73e0fd02012-04-04 11:46:38 +08002092
Jon Salz0697cbf2012-07-04 15:14:04 +08002093 if self.test_list.options.auto_run_on_keypress:
2094 self.auto_run(starting_at=test)
2095 else:
2096 self.run_tests(test)
Jon Salz73e0fd02012-04-04 11:46:38 +08002097
Wei-Ning Huang38b75f02015-02-25 18:25:14 +08002098 def handle_key_filter_mode(self, event):
2099 if self.key_filter:
2100 if getattr(event, 'enabled'):
2101 self.key_filter.Start()
2102 else:
2103 self.key_filter.Stop()
2104
Jon Salz0697cbf2012-07-04 15:14:04 +08002105 def wait(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002106 """Waits for all pending invocations.
Jon Salz0697cbf2012-07-04 15:14:04 +08002107
2108 Useful for testing.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002109 """
Jon Salz1acc8742012-07-17 17:45:55 +08002110 while self.invocations:
2111 for k, v in self.invocations.iteritems():
2112 logging.info('Waiting for %s to complete...', k)
2113 v.thread.join()
2114 self.reap_completed_tests()
Jon Salz0697cbf2012-07-04 15:14:04 +08002115
Claire Changd1961a22015-08-05 16:15:55 +08002116 def test_fail(self, test):
Hung-Te Lin410f70a2015-12-15 14:53:42 +08002117 self.dut.hooks.OnTestFailure(test)
Claire Changd1961a22015-08-05 16:15:55 +08002118 if self.link_manager:
2119 self.link_manager.UpdateStatus(False)
2120
Hung-Te Linf2f78f72012-02-08 19:27:11 +08002121if __name__ == '__main__':
Peter Ammona3d298c2014-09-23 10:11:02 -07002122 Goofy.run_main_and_exit()