blob: 5a08bbbbdc172cd41e30a95e35f76b1cde579cda [file] [log] [blame]
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001#!/usr/bin/python -u
Hung-Te Linf2f78f72012-02-08 19:27:11 +08002# -*- coding: utf-8 -*-
3#
Jon Salz37eccbd2012-05-25 16:06:52 +08004# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Hung-Te Linf2f78f72012-02-08 19:27:11 +08005# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08008"""The main factory flow that runs the factory test and finalizes a device."""
Hung-Te Linf2f78f72012-02-08 19:27:11 +08009
Joel Kitchingb85ed7f2014-10-08 18:24:39 +080010from __future__ import print_function
11
Jon Salze12c2b32013-06-25 16:24:34 +080012import glob
Jon Salz0405ab52012-03-16 15:26:52 +080013import logging
14import os
Jon Salze12c2b32013-06-25 16:24:34 +080015import shutil
Jon Salz77c151e2012-08-28 07:20:37 +080016import signal
Jon Salz0405ab52012-03-16 15:26:52 +080017import sys
Jon Salzeff94182013-06-19 15:06:28 +080018import syslog
Jon Salz0405ab52012-03-16 15:26:52 +080019import threading
20import time
21import traceback
Jon Salz258a40c2012-04-19 12:34:01 +080022import uuid
Jon Salzb10cf512012-08-09 17:29:21 +080023from xmlrpclib import Binary
Hung-Te Linf2f78f72012-02-08 19:27:11 +080024from collections import deque
25from optparse import OptionParser
Hung-Te Linf2f78f72012-02-08 19:27:11 +080026
Jon Salz0697cbf2012-07-04 15:14:04 +080027import factory_common # pylint: disable=W0611
Hung-Te Lin91492a12014-11-25 18:56:30 +080028from cros.factory.test import event_log
Chun-Ta Lin5d12b592015-06-30 00:54:23 -070029from cros.factory.test.event_log import EventLog, FloatDigit, GetBootSequence
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
Hung-Te Lin6a72c642015-12-13 22:09:09 +080043from cros.factory.test import dut
jcliangcd688182012-08-20 21:01:26 +080044from cros.factory.test import factory
Jon Salz670ce062014-05-16 15:53:50 +080045from cros.factory.test import phase
Jon Salz51528e12012-07-02 18:54:45 +080046from cros.factory.test import shopfloor
Hung-Te Lin6a72c642015-12-13 22:09:09 +080047from cros.factory.test import state
Jon Salz128b0932013-07-03 16:55:26 +080048from cros.factory.test.test_lists import test_lists
Ricky Liang6fe218c2013-12-27 15:17:17 +080049from cros.factory.test.e2e_test.common import (
50 AutomationMode, AutomationModePrompt, ParseAutomationMode)
Jon Salz83591782012-06-26 11:09:58 +080051from cros.factory.test.event import Event
52from cros.factory.test.event import EventClient
53from cros.factory.test.event import EventServer
Hung-Te Lin91492a12014-11-25 18:56:30 +080054from cros.factory.test.event_log_watcher import EventLogWatcher
jcliangcd688182012-08-20 21:01:26 +080055from cros.factory.test.factory import TestState
Hung-Te Linc367ac02015-12-22 19:33:23 +080056from cros.factory.test.utils.charge_manager import ChargeManager
57from cros.factory.test.utils.core_dump_manager import CoreDumpManager
58from cros.factory.test.utils.cpufreq_manager import CpufreqManager
Dean Liao592e4d52013-01-10 20:06:39 +080059from cros.factory.tools.key_filter import KeyFilter
Hung-Te Lind3ee0102015-12-28 17:21:50 +080060from cros.factory.tools import disk_space
Hung-Te Linf707b242016-01-08 23:11:42 +080061from cros.factory.utils import debug_utils
Jon Salz2af235d2013-06-24 14:47:21 +080062from cros.factory.utils import file_utils
Joel Kitchingb85ed7f2014-10-08 18:24:39 +080063from cros.factory.utils import net_utils
Hung-Te Lin4e6357c2016-01-08 14:32:00 +080064from cros.factory.utils import process_utils
65from cros.factory.utils import sys_utils
66from cros.factory.utils import time_utils
Hung-Te Linf707b242016-01-08 23:11:42 +080067from cros.factory.utils import type_utils
Hung-Te Linf2f78f72012-02-08 19:27:11 +080068
69
Hung-Te Linf2f78f72012-02-08 19:27:11 +080070HWID_CFG_PATH = '/usr/local/share/chromeos-hwid/cfg'
Ricky Liang45c73e72015-01-15 15:00:30 +080071CACHES_DIR = os.path.join(factory.get_state_root(), 'caches')
Hung-Te Linf2f78f72012-02-08 19:27:11 +080072
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +080073CLEANUP_LOGS_PAUSED = '/var/lib/cleanup_logs_paused'
74
Jon Salz5c344f62012-07-13 14:31:16 +080075# Value for tests_after_shutdown that forces auto-run (e.g., after
76# a factory update, when the available set of tests might change).
77FORCE_AUTO_RUN = 'force_auto_run'
78
Justin Chuang83813982013-05-13 01:26:32 +080079# Sync disks when battery level is higher than this value.
80# Otherwise, power loss during disk sync operation may incur even worse outcome.
81MIN_BATTERY_LEVEL_FOR_DISK_SYNC = 1.0
82
Ricky Liang45c73e72015-01-15 15:00:30 +080083MAX_CRASH_FILE_SIZE = 64 * 1024
Jon Salze12c2b32013-06-25 16:24:34 +080084
Hung-Te Linf707b242016-01-08 23:11:42 +080085Status = type_utils.Enum(['UNINITIALIZED', 'INITIALIZING', 'RUNNING',
Jon Salzd7550792013-07-12 05:49:27 +080086 'TERMINATING', 'TERMINATED'])
87
Ricky Liang45c73e72015-01-15 15:00:30 +080088
Hung-Te Linf2f78f72012-02-08 19:27:11 +080089def get_hwid_cfg():
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +080090 """Returns the HWID config tag, or an empty string if none can be found."""
Jon Salz0697cbf2012-07-04 15:14:04 +080091 if 'CROS_HWID' in os.environ:
92 return os.environ['CROS_HWID']
93 if os.path.exists(HWID_CFG_PATH):
Ricky Liang45c73e72015-01-15 15:00:30 +080094 with open(HWID_CFG_PATH, 'r') as hwid_cfg_handle:
Jon Salz0697cbf2012-07-04 15:14:04 +080095 return hwid_cfg_handle.read().strip()
96 return ''
Hung-Te Linf2f78f72012-02-08 19:27:11 +080097
98
Jon Salz73e0fd02012-04-04 11:46:38 +080099_inited_logging = False
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800100
Ricky Liang45c73e72015-01-15 15:00:30 +0800101
Peter Ammon1e1ec572014-06-26 17:56:32 -0700102class Goofy(GoofyBase):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800103 """The main factory flow.
Jon Salz0697cbf2012-07-04 15:14:04 +0800104
105 Note that all methods in this class must be invoked from the main
106 (event) thread. Other threads, such as callbacks and TestInvocation
107 methods, should instead post events on the run queue.
108
109 TODO: Unit tests. (chrome-os-partner:7409)
110
111 Properties:
112 uuid: A unique UUID for this invocation of Goofy.
113 state_instance: An instance of FactoryState.
114 state_server: The FactoryState XML/RPC server.
115 state_server_thread: A thread running state_server.
116 event_server: The EventServer socket server.
117 event_server_thread: A thread running event_server.
118 event_client: A client to the event server.
119 connection_manager: The connection_manager object.
Cheng-Yi Chiang835f2682013-05-06 22:15:48 +0800120 system_log_manager: The SystemLogManager object.
121 core_dump_manager: The CoreDumpManager object.
Jon Salz0697cbf2012-07-04 15:14:04 +0800122 ui_process: The factory ui process object.
Jon Salz0697cbf2012-07-04 15:14:04 +0800123 invocations: A map from FactoryTest objects to the corresponding
124 TestInvocations objects representing active tests.
125 tests_to_run: A deque of tests that should be run when the current
126 test(s) complete.
127 options: Command-line options.
128 args: Command-line args.
129 test_list: The test list.
Jon Salz128b0932013-07-03 16:55:26 +0800130 test_lists: All new-style test lists.
Ricky Liang4bff3e32014-02-20 18:46:11 +0800131 run_id: The identifier for latest test run.
132 scheduled_run_tests: The list of tests scheduled for latest test run.
Jon Salz0697cbf2012-07-04 15:14:04 +0800133 event_handlers: Map of Event.Type to the method used to handle that
134 event. If the method has an 'event' argument, the event is passed
135 to the handler.
Jon Salz3c493bb2013-02-07 17:24:58 +0800136 last_log_disk_space_message: The last message we logged about disk space
137 (to avoid duplication).
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +0800138 last_kick_sync_time: The last time to kick system_log_manager to sync
139 because of core dump files (to avoid kicking too soon then abort the
140 sync.)
Jon Salz416f9cc2013-05-10 18:32:50 +0800141 hooks: A Hooks object containing hooks for various Goofy actions.
Jon Salzd7550792013-07-12 05:49:27 +0800142 status: The current Goofy status (a member of the Status enum).
Peter Ammon948b7172014-07-15 12:43:06 -0700143 link_manager: Instance of PresenterLinkManager for communicating
144 with GoofyPresenter
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800145 """
Ricky Liang45c73e72015-01-15 15:00:30 +0800146
Jon Salz0697cbf2012-07-04 15:14:04 +0800147 def __init__(self):
Peter Ammon1e1ec572014-06-26 17:56:32 -0700148 super(Goofy, self).__init__()
Jon Salz0697cbf2012-07-04 15:14:04 +0800149 self.uuid = str(uuid.uuid4())
150 self.state_instance = None
151 self.state_server = None
152 self.state_server_thread = None
Jon Salz16d10542012-07-23 12:18:45 +0800153 self.goofy_rpc = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800154 self.event_server = None
155 self.event_server_thread = None
156 self.event_client = None
157 self.connection_manager = None
Vic Yang4953fc12012-07-26 16:19:53 +0800158 self.charge_manager = None
Dean Liao88b93192014-10-23 19:37:41 +0800159 self._can_charge = True
Jon Salz8fa8e832012-07-13 19:04:09 +0800160 self.time_sanitizer = None
161 self.time_synced = False
Jon Salz0697cbf2012-07-04 15:14:04 +0800162 self.log_watcher = None
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800163 self.system_log_manager = None
Cheng-Yi Chiang835f2682013-05-06 22:15:48 +0800164 self.core_dump_manager = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800165 self.event_log = None
Vic Yange2c76a82014-10-30 12:48:19 -0700166 self.autotest_prespawner = None
167 self.pytest_prespawner = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800168 self.ui_process = None
Vic Yanga3cecf82014-12-26 00:44:21 -0800169 self._ui_initialized = False
Jon Salzc79a9982012-08-30 04:42:01 +0800170 self.dummy_shopfloor = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800171 self.invocations = {}
172 self.tests_to_run = deque()
173 self.visible_test = None
174 self.chrome = None
Jon Salz416f9cc2013-05-10 18:32:50 +0800175 self.hooks = None
Vic Yangd8990da2013-06-27 16:57:43 +0800176 self.cpu_usage_watcher = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800177
178 self.options = None
179 self.args = None
180 self.test_list = None
Jon Salz128b0932013-07-03 16:55:26 +0800181 self.test_lists = None
Ricky Liang4bff3e32014-02-20 18:46:11 +0800182 self.run_id = None
183 self.scheduled_run_tests = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800184 self.env = None
Jon Salzb22d1172012-08-06 10:38:57 +0800185 self.last_idle = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800186 self.last_shutdown_time = None
cychiang21886742012-07-05 15:16:32 +0800187 self.last_update_check = None
Cheng-Yi Chiang194d3c02015-03-16 14:37:15 +0800188 self._suppress_periodic_update_messages = False
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +0800189 self._suppress_event_log_error_messages = False
Jon Salz8fa8e832012-07-13 19:04:09 +0800190 self.last_sync_time = None
Jon Salzb92c5112012-09-21 15:40:11 +0800191 self.last_log_disk_space_time = None
Jon Salz3c493bb2013-02-07 17:24:58 +0800192 self.last_log_disk_space_message = None
Justin Chuang83813982013-05-13 01:26:32 +0800193 self.last_check_battery_time = None
194 self.last_check_battery_message = None
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +0800195 self.last_kick_sync_time = None
Vic Yang311ddb82012-09-26 12:08:28 +0800196 self.exclusive_items = set()
Jon Salz0f996602012-10-03 15:26:48 +0800197 self.event_log = None
Dean Liao592e4d52013-01-10 20:06:39 +0800198 self.key_filter = None
Jon Salzce6a7f82013-06-10 18:22:54 +0800199 self.cpufreq_manager = None
Jon Salzd7550792013-07-12 05:49:27 +0800200 self.status = Status.UNINITIALIZED
Ricky Liang36512a32014-07-25 11:47:04 +0800201 self.ready_for_ui_connection = False
Peter Ammon1e1ec572014-06-26 17:56:32 -0700202 self.link_manager = None
Hung-Te Linef7f2be2015-07-20 20:38:51 +0800203 self.is_restart_requested = False
Jon Salz0697cbf2012-07-04 15:14:04 +0800204
Hung-Te Lin6a72c642015-12-13 22:09:09 +0800205 # TODO(hungte) Support controlling remote DUT.
206 self.dut = dut.Create()
207
Jon Salz85a39882012-07-05 16:45:04 +0800208 def test_or_root(event, parent_or_group=True):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800209 """Returns the test affected by a particular event.
Jon Salz85a39882012-07-05 16:45:04 +0800210
211 Args:
212 event: The event containing an optional 'path' attribute.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800213 parent_or_group: If True, returns the top-level parent for a test (the
Jon Salz85a39882012-07-05 16:45:04 +0800214 root node of the tests that need to be run together if the given test
215 path is to be run).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800216 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800217 try:
218 path = event.path
219 except AttributeError:
220 path = None
221
222 if path:
Jon Salz85a39882012-07-05 16:45:04 +0800223 test = self.test_list.lookup_path(path)
224 if parent_or_group:
225 test = test.get_top_level_parent_or_group()
226 return test
Jon Salz0697cbf2012-07-04 15:14:04 +0800227 else:
228 return self.test_list
229
230 self.event_handlers = {
Ricky Liang45c73e72015-01-15 15:00:30 +0800231 Event.Type.SWITCH_TEST: self.handle_switch_test,
232 Event.Type.SHOW_NEXT_ACTIVE_TEST:
233 lambda event: self.show_next_active_test(),
234 Event.Type.RESTART_TESTS:
235 lambda event: self.restart_tests(root=test_or_root(event)),
236 Event.Type.AUTO_RUN:
237 lambda event: self.auto_run(root=test_or_root(event)),
238 Event.Type.RE_RUN_FAILED:
239 lambda event: self.re_run_failed(root=test_or_root(event)),
240 Event.Type.RUN_TESTS_WITH_STATUS:
241 lambda event: self.run_tests_with_status(
242 event.status,
243 root=test_or_root(event)),
244 Event.Type.REVIEW:
245 lambda event: self.show_review_information(),
246 Event.Type.UPDATE_SYSTEM_INFO:
247 lambda event: self.update_system_info(),
248 Event.Type.STOP:
249 lambda event: self.stop(root=test_or_root(event, False),
250 fail=getattr(event, 'fail', False),
251 reason=getattr(event, 'reason', None)),
252 Event.Type.SET_VISIBLE_TEST:
253 lambda event: self.set_visible_test(
254 self.test_list.lookup_path(event.path)),
255 Event.Type.CLEAR_STATE:
256 lambda event: self.clear_state(
257 self.test_list.lookup_path(event.path)),
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800258 Event.Type.KEY_FILTER_MODE: self.handle_key_filter_mode,
Jon Salz0697cbf2012-07-04 15:14:04 +0800259 }
260
Jon Salz0697cbf2012-07-04 15:14:04 +0800261 self.web_socket_manager = None
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800262 self.terminal_manager = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800263
264 def destroy(self):
Ricky Liang74237a02014-09-18 15:11:23 +0800265 """Performs any shutdown tasks. Overrides base class method."""
Jon Salzd7550792013-07-12 05:49:27 +0800266 self.status = Status.TERMINATING
Jon Salz0697cbf2012-07-04 15:14:04 +0800267 if self.chrome:
268 self.chrome.kill()
269 self.chrome = None
Jon Salzc79a9982012-08-30 04:42:01 +0800270 if self.dummy_shopfloor:
271 self.dummy_shopfloor.kill()
272 self.dummy_shopfloor = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800273 if self.ui_process:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800274 process_utils.KillProcessTree(self.ui_process, 'ui')
Jon Salz0697cbf2012-07-04 15:14:04 +0800275 self.ui_process = None
276 if self.web_socket_manager:
277 logging.info('Stopping web sockets')
278 self.web_socket_manager.close()
279 self.web_socket_manager = None
280 if self.state_server_thread:
281 logging.info('Stopping state server')
282 self.state_server.shutdown()
283 self.state_server_thread.join()
284 self.state_server.server_close()
285 self.state_server_thread = None
286 if self.state_instance:
287 self.state_instance.close()
288 if self.event_server_thread:
289 logging.info('Stopping event server')
290 self.event_server.shutdown() # pylint: disable=E1101
291 self.event_server_thread.join()
292 self.event_server.server_close()
293 self.event_server_thread = None
294 if self.log_watcher:
295 if self.log_watcher.IsThreadStarted():
296 self.log_watcher.StopWatchThread()
297 self.log_watcher = None
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800298 if self.system_log_manager:
299 if self.system_log_manager.IsThreadRunning():
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +0800300 self.system_log_manager.Stop()
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800301 self.system_log_manager = None
Vic Yange2c76a82014-10-30 12:48:19 -0700302 if self.autotest_prespawner:
303 logging.info('Stopping autotest prespawner')
304 self.autotest_prespawner.stop()
305 self.autotest_prespawner = None
306 if self.pytest_prespawner:
307 logging.info('Stopping pytest prespawner')
308 self.pytest_prespawner.stop()
309 self.pytest_prespawner = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800310 if self.event_client:
311 logging.info('Closing event client')
312 self.event_client.close()
313 self.event_client = None
Jon Salzddf0d052013-06-18 12:52:44 +0800314 if self.cpufreq_manager:
315 self.cpufreq_manager.Stop()
Jon Salz0697cbf2012-07-04 15:14:04 +0800316 if self.event_log:
317 self.event_log.Close()
318 self.event_log = None
Dean Liao592e4d52013-01-10 20:06:39 +0800319 if self.key_filter:
320 self.key_filter.Stop()
Vic Yangd8990da2013-06-27 16:57:43 +0800321 if self.cpu_usage_watcher:
322 self.cpu_usage_watcher.terminate()
Peter Ammon1e1ec572014-06-26 17:56:32 -0700323 if self.link_manager:
324 self.link_manager.Stop()
325 self.link_manager = None
Dean Liao592e4d52013-01-10 20:06:39 +0800326
Peter Ammon1e1ec572014-06-26 17:56:32 -0700327 super(Goofy, self).destroy()
Jon Salz0697cbf2012-07-04 15:14:04 +0800328 logging.info('Done destroying Goofy')
Jon Salzd7550792013-07-12 05:49:27 +0800329 self.status = Status.TERMINATED
Jon Salz0697cbf2012-07-04 15:14:04 +0800330
331 def start_state_server(self):
Jon Salz2af235d2013-06-24 14:47:21 +0800332 # Before starting state server, remount stateful partitions with
333 # no commit flag. The default commit time (commit=600) makes corruption
334 # too likely.
Hung-Te Lin1968d9c2016-01-08 22:55:46 +0800335 sys_utils.ResetCommitTime()
Jon Salz2af235d2013-06-24 14:47:21 +0800336
Jon Salz0697cbf2012-07-04 15:14:04 +0800337 self.state_instance, self.state_server = (
Ricky Liang45c73e72015-01-15 15:00:30 +0800338 state.create_server(bind_address='0.0.0.0'))
Jon Salz16d10542012-07-23 12:18:45 +0800339 self.goofy_rpc = GoofyRPC(self)
340 self.goofy_rpc.RegisterMethods(self.state_instance)
Jon Salz0697cbf2012-07-04 15:14:04 +0800341 logging.info('Starting state server')
342 self.state_server_thread = threading.Thread(
Ricky Liang45c73e72015-01-15 15:00:30 +0800343 target=self.state_server.serve_forever,
344 name='StateServer')
Jon Salz0697cbf2012-07-04 15:14:04 +0800345 self.state_server_thread.start()
346
347 def start_event_server(self):
348 self.event_server = EventServer()
349 logging.info('Starting factory event server')
350 self.event_server_thread = threading.Thread(
Ricky Liang45c73e72015-01-15 15:00:30 +0800351 target=self.event_server.serve_forever,
352 name='EventServer') # pylint: disable=E1101
Jon Salz0697cbf2012-07-04 15:14:04 +0800353 self.event_server_thread.start()
354
355 self.event_client = EventClient(
Ricky Liang45c73e72015-01-15 15:00:30 +0800356 callback=self.handle_event, event_loop=self.run_queue)
Jon Salz0697cbf2012-07-04 15:14:04 +0800357
358 self.web_socket_manager = WebSocketManager(self.uuid)
Ricky Liang45c73e72015-01-15 15:00:30 +0800359 self.state_server.add_handler('/event',
360 self.web_socket_manager.handle_web_socket)
Jon Salz0697cbf2012-07-04 15:14:04 +0800361
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800362 def start_terminal_server(self):
363 self.terminal_manager = TerminalManager()
364 self.state_server.add_handler('/pty',
365 self.terminal_manager.handle_web_socket)
366
Jon Salz0697cbf2012-07-04 15:14:04 +0800367 def start_ui(self):
368 ui_proc_args = [
Ricky Liang45c73e72015-01-15 15:00:30 +0800369 os.path.join(factory.FACTORY_PACKAGE_PATH, 'test', 'ui.py'),
370 self.options.test_list
371 ]
Jon Salz0697cbf2012-07-04 15:14:04 +0800372 if self.options.verbose:
373 ui_proc_args.append('-v')
374 logging.info('Starting ui %s', ui_proc_args)
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800375 self.ui_process = process_utils.Spawn(ui_proc_args)
Jon Salz0697cbf2012-07-04 15:14:04 +0800376 logging.info('Waiting for UI to come up...')
377 self.event_client.wait(
Ricky Liang45c73e72015-01-15 15:00:30 +0800378 lambda event: event.type == Event.Type.UI_READY)
Jon Salz0697cbf2012-07-04 15:14:04 +0800379 logging.info('UI has started')
380
381 def set_visible_test(self, test):
382 if self.visible_test == test:
383 return
Jon Salz2f2d42c2012-07-30 12:30:34 +0800384 if test and not test.has_ui:
385 return
Jon Salz0697cbf2012-07-04 15:14:04 +0800386
387 if test:
388 test.update_state(visible=True)
389 if self.visible_test:
390 self.visible_test.update_state(visible=False)
391 self.visible_test = test
392
Ricky Liang48e47f92014-02-26 19:31:51 +0800393 def log_startup_messages(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800394 """Logs the tail of var/log/messages and mosys and EC console logs."""
Jon Salzd4306c82012-11-30 15:16:36 +0800395 # TODO(jsalz): This is mostly a copy-and-paste of code in init_states,
396 # for factory-3004.B only. Consolidate and merge back to ToT.
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800397 if sys_utils.InChroot():
Jon Salzd4306c82012-11-30 15:16:36 +0800398 return
399
400 try:
Hung-Te Lin1a4e30c2016-01-08 23:25:10 +0800401 var_log_messages = sys_utils.GetVarLogMessagesBeforeReboot()
Jon Salzd4306c82012-11-30 15:16:36 +0800402 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +0800403 'Tail of /var/log/messages before last reboot:\n'
404 '%s', ('\n'.join(
405 ' ' + x for x in var_log_messages)))
Jon Salzd4306c82012-11-30 15:16:36 +0800406 except: # pylint: disable=W0702
407 logging.exception('Unable to grok /var/log/messages')
408
409 try:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800410 mosys_log = process_utils.Spawn(
Jon Salzd4306c82012-11-30 15:16:36 +0800411 ['mosys', 'eventlog', 'list'],
412 read_stdout=True, log_stderr_on_error=True).stdout_data
413 logging.info('System eventlog from mosys:\n%s\n', mosys_log)
414 except: # pylint: disable=W0702
415 logging.exception('Unable to read mosys eventlog')
416
Dean Liao88b93192014-10-23 19:37:41 +0800417 self.log_ec_console()
418 self.log_ec_panic_info()
419
420 @staticmethod
421 def log_ec_console():
422 """Logs EC console log into logging.info.
423
424 It logs an error message in logging.exception if an exception is raised
425 when getting EC console log.
426 For unsupported device, it logs unsupport message in logging.info
427
428 Returns:
429 EC console log string.
430 """
Jon Salzd4306c82012-11-30 15:16:36 +0800431 try:
Hung-Te Linb3a09642015-12-14 18:57:23 +0800432 ec_console_log = dut.Create().ec.GetECConsoleLog()
Jon Salzd4306c82012-11-30 15:16:36 +0800433 logging.info('EC console log after reboot:\n%s\n', ec_console_log)
Dean Liao88b93192014-10-23 19:37:41 +0800434 return ec_console_log
435 except NotImplementedError:
436 logging.info('EC console log not supported')
Jon Salzd4306c82012-11-30 15:16:36 +0800437 except: # pylint: disable=W0702
438 logging.exception('Error retrieving EC console log')
439
Dean Liao88b93192014-10-23 19:37:41 +0800440 @staticmethod
441 def log_ec_panic_info():
442 """Logs EC panic info into logging.info.
443
444 It logs an error message in logging.exception if an exception is raised
445 when getting EC panic info.
446 For unsupported device, it logs unsupport message in logging.info
447
448 Returns:
449 EC panic info string.
450 """
Vic Yang079f9872013-07-01 11:32:00 +0800451 try:
Hung-Te Linb3a09642015-12-14 18:57:23 +0800452 ec_panic_info = dut.Create().ec.GetECPanicInfo()
Vic Yang079f9872013-07-01 11:32:00 +0800453 logging.info('EC panic info after reboot:\n%s\n', ec_panic_info)
Dean Liao88b93192014-10-23 19:37:41 +0800454 return ec_panic_info
455 except NotImplementedError:
456 logging.info('EC panic info is not supported')
Vic Yang079f9872013-07-01 11:32:00 +0800457 except: # pylint: disable=W0702
458 logging.exception('Error retrieving EC panic info')
459
Ricky Liang48e47f92014-02-26 19:31:51 +0800460 def shutdown(self, operation):
461 """Starts shutdown procedure.
462
463 Args:
Vic (Chun-Ju) Yang05b0d952014-04-28 17:39:09 +0800464 operation: The shutdown operation (reboot, full_reboot, or halt).
Ricky Liang48e47f92014-02-26 19:31:51 +0800465 """
466 active_tests = []
467 for test in self.test_list.walk():
468 if not test.is_leaf():
469 continue
470
471 test_state = test.get_state()
472 if test_state.status == TestState.ACTIVE:
473 active_tests.append(test)
474
Ricky Liang48e47f92014-02-26 19:31:51 +0800475 if not (len(active_tests) == 1 and
476 isinstance(active_tests[0], factory.ShutdownStep)):
477 logging.error(
478 'Calling Goofy shutdown outside of the shutdown factory test')
479 return
480
481 logging.info('Start Goofy shutdown (%s)', operation)
482 # Save pending test list in the state server
483 self.state_instance.set_shared_data(
484 'tests_after_shutdown',
485 [t.path for t in self.tests_to_run])
486 # Save shutdown time
487 self.state_instance.set_shared_data('shutdown_time', time.time())
488
489 with self.env.lock:
490 self.event_log.Log('shutdown', operation=operation)
491 shutdown_result = self.env.shutdown(operation)
492 if shutdown_result:
493 # That's all, folks!
Peter Ammon1e1ec572014-06-26 17:56:32 -0700494 self.run_enqueue(None)
Ricky Liang48e47f92014-02-26 19:31:51 +0800495 else:
496 # Just pass (e.g., in the chroot).
497 self.state_instance.set_shared_data('tests_after_shutdown', None)
498 # Send event with no fields to indicate that there is no
499 # longer a pending shutdown.
500 self.event_client.post_event(Event(Event.Type.PENDING_SHUTDOWN))
501
502 def handle_shutdown_complete(self, test):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800503 """Handles the case where a shutdown was detected during a shutdown step.
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800504
Ricky Liang6fe218c2013-12-27 15:17:17 +0800505 Args:
506 test: The ShutdownStep.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800507 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800508 test_state = test.update_state(increment_shutdown_count=1)
509 logging.info('Detected shutdown (%d of %d)',
Ricky Liang48e47f92014-02-26 19:31:51 +0800510 test_state.shutdown_count, test.iterations)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800511
Ricky Liang48e47f92014-02-26 19:31:51 +0800512 # Insert current shutdown test at the front of the list of tests to run
513 # after shutdown. This is to continue on post-shutdown verification in the
514 # shutdown step.
515 tests_after_shutdown = self.state_instance.get_shared_data(
516 'tests_after_shutdown', optional=True)
517 if not tests_after_shutdown:
518 self.state_instance.set_shared_data('tests_after_shutdown', [test.path])
519 elif isinstance(tests_after_shutdown, list):
520 self.state_instance.set_shared_data(
521 'tests_after_shutdown', [test.path] + tests_after_shutdown)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800522
Ricky Liang48e47f92014-02-26 19:31:51 +0800523 # Set 'post_shutdown' to inform shutdown test that a shutdown just occurred.
Ricky Liangb7eb8772014-09-15 18:05:22 +0800524 self.state_instance.set_shared_data(
525 state.POST_SHUTDOWN_TAG % test.path,
526 self.state_instance.get_test_state(test.path).invocation)
Jon Salz258a40c2012-04-19 12:34:01 +0800527
Jon Salz0697cbf2012-07-04 15:14:04 +0800528 def init_states(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800529 """Initializes all states on startup."""
Jon Salz0697cbf2012-07-04 15:14:04 +0800530 for test in self.test_list.get_all_tests():
531 # Make sure the state server knows about all the tests,
532 # defaulting to an untested state.
533 test.update_state(update_parent=False, visible=False)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800534
Jon Salz0697cbf2012-07-04 15:14:04 +0800535 var_log_messages = None
Vic Yanga9c32212012-08-16 20:07:54 +0800536 mosys_log = None
Vic Yange4c275d2012-08-28 01:50:20 +0800537 ec_console_log = None
Vic Yang079f9872013-07-01 11:32:00 +0800538 ec_panic_info = None
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800539
Jon Salz0697cbf2012-07-04 15:14:04 +0800540 # Any 'active' tests should be marked as failed now.
541 for test in self.test_list.walk():
Jon Salza6711d72012-07-18 14:33:03 +0800542 if not test.is_leaf():
543 # Don't bother with parents; they will be updated when their
544 # children are updated.
545 continue
546
Jon Salz0697cbf2012-07-04 15:14:04 +0800547 test_state = test.get_state()
548 if test_state.status != TestState.ACTIVE:
549 continue
550 if isinstance(test, factory.ShutdownStep):
551 # Shutdown while the test was active - that's good.
Ricky Liang48e47f92014-02-26 19:31:51 +0800552 self.handle_shutdown_complete(test)
Jon Salz0697cbf2012-07-04 15:14:04 +0800553 else:
554 # Unexpected shutdown. Grab /var/log/messages for context.
555 if var_log_messages is None:
556 try:
557 var_log_messages = (
Hung-Te Lin1a4e30c2016-01-08 23:25:10 +0800558 sys_utils.GetVarLogMessagesBeforeReboot())
Jon Salz0697cbf2012-07-04 15:14:04 +0800559 # Write it to the log, to make it easier to
560 # correlate with /var/log/messages.
561 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +0800562 'Unexpected shutdown. '
563 'Tail of /var/log/messages before last reboot:\n'
564 '%s', ('\n'.join(
565 ' ' + x for x in var_log_messages)))
Jon Salz0697cbf2012-07-04 15:14:04 +0800566 except: # pylint: disable=W0702
567 logging.exception('Unable to grok /var/log/messages')
568 var_log_messages = []
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800569
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800570 if mosys_log is None and not sys_utils.InChroot():
Jon Salz008f4ea2012-08-28 05:39:45 +0800571 try:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800572 mosys_log = process_utils.Spawn(
Jon Salz008f4ea2012-08-28 05:39:45 +0800573 ['mosys', 'eventlog', 'list'],
574 read_stdout=True, log_stderr_on_error=True).stdout_data
575 # Write it to the log also.
576 logging.info('System eventlog from mosys:\n%s\n', mosys_log)
577 except: # pylint: disable=W0702
578 logging.exception('Unable to read mosys eventlog')
Vic Yanga9c32212012-08-16 20:07:54 +0800579
Vic Yange4c275d2012-08-28 01:50:20 +0800580 if ec_console_log is None:
Dean Liao88b93192014-10-23 19:37:41 +0800581 ec_console_log = self.log_ec_console()
Vic Yange4c275d2012-08-28 01:50:20 +0800582
Vic Yang079f9872013-07-01 11:32:00 +0800583 if ec_panic_info is None:
Dean Liao88b93192014-10-23 19:37:41 +0800584 ec_panic_info = self.log_ec_panic_info()
Vic Yang079f9872013-07-01 11:32:00 +0800585
Jon Salz0697cbf2012-07-04 15:14:04 +0800586 error_msg = 'Unexpected shutdown while test was running'
587 self.event_log.Log('end_test',
Ricky Liang45c73e72015-01-15 15:00:30 +0800588 path=test.path,
589 status=TestState.FAILED,
590 invocation=test.get_state().invocation,
591 error_msg=error_msg,
592 var_log_messages='\n'.join(var_log_messages),
593 mosys_log=mosys_log)
Jon Salz0697cbf2012-07-04 15:14:04 +0800594 test.update_state(
Ricky Liang45c73e72015-01-15 15:00:30 +0800595 status=TestState.FAILED,
596 error_msg=error_msg)
Chun-Ta Lin87c2dac2015-05-02 01:35:01 -0700597 # Trigger the OnTestFailure callback.
Claire Changd1961a22015-08-05 16:15:55 +0800598 self.run_queue.put(lambda: self.test_fail(test))
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800599
Jon Salz50efe942012-07-26 11:54:10 +0800600 if not test.never_fails:
601 # For "never_fails" tests (such as "Start"), don't cancel
602 # pending tests, since reboot is expected.
603 factory.console.info('Unexpected shutdown while test %s '
604 'running; cancelling any pending tests',
605 test.path)
606 self.state_instance.set_shared_data('tests_after_shutdown', [])
Jon Salz69806bb2012-07-20 18:05:02 +0800607
Jon Salz008f4ea2012-08-28 05:39:45 +0800608 self.update_skipped_tests()
609
610 def update_skipped_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800611 """Updates skipped states based on run_if."""
Jon Salz885dcac2013-07-23 16:39:50 +0800612 env = TestArgEnv()
Ricky Liang45c73e72015-01-15 15:00:30 +0800613
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800614 def _evaluate_skip_from_run_if(test):
615 """Returns the run_if evaluation of the test.
616
617 Args:
618 test: A FactoryTest object.
619
620 Returns:
621 The run_if evaluation result. Returns False if the test has no
622 run_if argument.
623 """
624 value = None
625 if test.run_if_expr:
626 try:
627 value = test.run_if_expr(env)
628 except: # pylint: disable=W0702
629 logging.exception('Unable to evaluate run_if expression for %s',
630 test.path)
631 # But keep going; we have no choice. This will end up
632 # always activating the test.
633 elif test.run_if_table_name:
634 try:
635 aux = shopfloor.get_selected_aux_data(test.run_if_table_name)
636 value = aux.get(test.run_if_col)
637 except ValueError:
638 # Not available; assume it shouldn't be skipped
639 pass
640
641 if value is None:
642 skip = False
643 else:
644 skip = (not value) ^ t.run_if_not
645 return skip
646
647 # Gets all run_if evaluation, and stores results in skip_map.
648 skip_map = dict()
Jon Salz008f4ea2012-08-28 05:39:45 +0800649 for t in self.test_list.walk():
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800650 skip_map[t.path] = _evaluate_skip_from_run_if(t)
Jon Salz885dcac2013-07-23 16:39:50 +0800651
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800652 # Propagates the skip value from root of tree and updates skip_map.
653 def _update_skip_map_from_node(test, skip_from_parent):
654 """Updates skip_map from a given node.
Jon Salz885dcac2013-07-23 16:39:50 +0800655
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800656 Given a FactoryTest node and the skip value from parent, updates the
657 skip value of current node in the skip_map if skip value from parent is
658 True. If this node has children, recursively propagate this value to all
659 its children, that is, all its subtests.
660 Note that this function only updates value in skip_map, not the actual
661 test_list tree.
Jon Salz008f4ea2012-08-28 05:39:45 +0800662
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800663 Args:
664 test: The given FactoryTest object. It is a node in the test_list tree.
665 skip_from_parent: The skip value which propagates from the parent of
666 input node.
667 """
668 skip_this_tree = skip_from_parent or skip_map[test.path]
669 if skip_this_tree:
670 logging.info('Skip from node %r', test.path)
671 skip_map[test.path] = True
672 if test.is_leaf():
673 return
674 # Propagates skip value to its subtests
675 for subtest in test.subtests:
676 _update_skip_map_from_node(subtest, skip_this_tree)
677
678 _update_skip_map_from_node(self.test_list, False)
679
680 # Updates the skip value from skip_map to test_list tree. Also, updates test
681 # status if needed.
682 for t in self.test_list.walk():
683 skip = skip_map[t.path]
684 test_state = t.get_state()
685 if ((not skip) and
686 (test_state.status == TestState.PASSED) and
687 (test_state.error_msg == TestState.SKIPPED_MSG)):
688 # It was marked as skipped before, but now we need to run it.
689 # Mark as untested.
690 t.update_state(skip=skip, status=TestState.UNTESTED, error_msg='')
691 else:
692 t.update_state(skip=skip)
Jon Salz008f4ea2012-08-28 05:39:45 +0800693
Jon Salz0697cbf2012-07-04 15:14:04 +0800694 def show_next_active_test(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800695 """Rotates to the next visible active test."""
Jon Salz0697cbf2012-07-04 15:14:04 +0800696 self.reap_completed_tests()
697 active_tests = [
Ricky Liang45c73e72015-01-15 15:00:30 +0800698 t for t in self.test_list.walk()
699 if t.is_leaf() and t.get_state().status == TestState.ACTIVE]
Jon Salz0697cbf2012-07-04 15:14:04 +0800700 if not active_tests:
701 return
Jon Salz4f6c7172012-06-11 20:45:36 +0800702
Jon Salz0697cbf2012-07-04 15:14:04 +0800703 try:
704 next_test = active_tests[
Ricky Liang45c73e72015-01-15 15:00:30 +0800705 (active_tests.index(self.visible_test) + 1) % len(active_tests)]
Jon Salz0697cbf2012-07-04 15:14:04 +0800706 except ValueError: # visible_test not present in active_tests
707 next_test = active_tests[0]
Jon Salz4f6c7172012-06-11 20:45:36 +0800708
Jon Salz0697cbf2012-07-04 15:14:04 +0800709 self.set_visible_test(next_test)
Jon Salz4f6c7172012-06-11 20:45:36 +0800710
Jon Salz0697cbf2012-07-04 15:14:04 +0800711 def handle_event(self, event):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800712 """Handles an event from the event server."""
Jon Salz0697cbf2012-07-04 15:14:04 +0800713 handler = self.event_handlers.get(event.type)
714 if handler:
715 handler(event)
716 else:
717 # We don't register handlers for all event types - just ignore
718 # this event.
719 logging.debug('Unbound event type %s', event.type)
Jon Salz4f6c7172012-06-11 20:45:36 +0800720
Vic Yangaabf9fd2013-04-09 18:56:13 +0800721 def check_critical_factory_note(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800722 """Returns True if the last factory note is critical."""
Vic Yangaabf9fd2013-04-09 18:56:13 +0800723 notes = self.state_instance.get_shared_data('factory_note', True)
724 return notes and notes[-1]['level'] == 'CRITICAL'
725
Hung-Te Linef7f2be2015-07-20 20:38:51 +0800726 def schedule_restart(self):
727 """Schedules a restart event when any invocation is completed."""
728 self.is_restart_requested = True
729
730 def invocation_completion(self):
731 """Callback when an invocation is completed."""
732 if self.is_restart_requested:
733 logging.info('Restart by scheduled event.')
734 self.is_restart_requested = False
735 self.restart_tests()
736 else:
737 self.run_next_test()
738
Jon Salz0697cbf2012-07-04 15:14:04 +0800739 def run_next_test(self):
henryhsu4cc6b022014-04-22 17:12:42 +0800740 """Runs the next eligible test (or tests) in self.tests_to_run.
741
742 We have three kinds of the next eligible test:
743 1. normal
744 2. backgroundable
745 3. force_background
746
747 And we have four situations of the ongoing invocations:
748 a. only a running normal test
749 b. all running tests are backgroundable
750 c. all running tests are force_background
751 d. all running tests are any combination of backgroundable and
752 force_background
753
754 When a test would like to be run, it must follow the rules:
755 [1] cannot run with [abd]
756 [2] cannot run with [a]
757 All the other combinations are allowed
758 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800759 self.reap_completed_tests()
Vic Yangaabf9fd2013-04-09 18:56:13 +0800760 if self.tests_to_run and self.check_critical_factory_note():
761 self.tests_to_run.clear()
762 return
Jon Salz0697cbf2012-07-04 15:14:04 +0800763 while self.tests_to_run:
Ricky Liang6fe218c2013-12-27 15:17:17 +0800764 logging.debug('Tests to run: %s', [x.path for x in self.tests_to_run])
Jon Salz94eb56f2012-06-12 18:01:12 +0800765
Jon Salz0697cbf2012-07-04 15:14:04 +0800766 test = self.tests_to_run[0]
Jon Salz94eb56f2012-06-12 18:01:12 +0800767
Jon Salz0697cbf2012-07-04 15:14:04 +0800768 if test in self.invocations:
769 logging.info('Next test %s is already running', test.path)
770 self.tests_to_run.popleft()
771 return
Jon Salz94eb56f2012-06-12 18:01:12 +0800772
Jon Salza1412922012-07-23 16:04:17 +0800773 for requirement in test.require_run:
774 for i in requirement.test.walk():
775 if i.get_state().status == TestState.ACTIVE:
Jon Salz304a75d2012-07-06 11:14:15 +0800776 logging.info('Waiting for active test %s to complete '
Jon Salza1412922012-07-23 16:04:17 +0800777 'before running %s', i.path, test.path)
Jon Salz304a75d2012-07-06 11:14:15 +0800778 return
779
henryhsu4cc6b022014-04-22 17:12:42 +0800780 def is_normal_test(test):
781 return not (test.backgroundable or test.force_background)
782
783 # [1] cannot run with [abd].
784 if self.invocations and is_normal_test(test) and any(
785 [not x.force_background for x in self.invocations]):
786 logging.info('Waiting for non-force_background tests to '
787 'complete before running %s', test.path)
788 return
789
790 # [2] cannot run with [a].
791 if self.invocations and test.backgroundable and any(
792 [is_normal_test(x) for x in self.invocations]):
793 logging.info('Waiting for normal tests to '
794 'complete before running %s', test.path)
Jon Salz0697cbf2012-07-04 15:14:04 +0800795 return
Jon Salz94eb56f2012-06-12 18:01:12 +0800796
Jon Salz3e6f5202012-10-15 15:08:29 +0800797 if test.get_state().skip:
798 factory.console.info('Skipping test %s', test.path)
799 test.update_state(status=TestState.PASSED,
800 error_msg=TestState.SKIPPED_MSG)
801 self.tests_to_run.popleft()
802 continue
803
Jon Salz0697cbf2012-07-04 15:14:04 +0800804 self.tests_to_run.popleft()
Jon Salz94eb56f2012-06-12 18:01:12 +0800805
Jon Salz304a75d2012-07-06 11:14:15 +0800806 untested = set()
Jon Salza1412922012-07-23 16:04:17 +0800807 for requirement in test.require_run:
808 for i in requirement.test.walk():
809 if i == test:
Jon Salz304a75d2012-07-06 11:14:15 +0800810 # We've hit this test itself; stop checking
811 break
Jon Salza1412922012-07-23 16:04:17 +0800812 if ((i.get_state().status == TestState.UNTESTED) or
813 (requirement.passed and i.get_state().status !=
814 TestState.PASSED)):
Jon Salz304a75d2012-07-06 11:14:15 +0800815 # Found an untested test; move on to the next
816 # element in require_run.
Jon Salza1412922012-07-23 16:04:17 +0800817 untested.add(i)
Jon Salz304a75d2012-07-06 11:14:15 +0800818 break
819
820 if untested:
821 untested_paths = ', '.join(sorted([x.path for x in untested]))
822 if self.state_instance.get_shared_data('engineering_mode',
823 optional=True):
824 # In engineering mode, we'll let it go.
825 factory.console.warn('In engineering mode; running '
826 '%s even though required tests '
827 '[%s] have not completed',
828 test.path, untested_paths)
829 else:
830 # Not in engineering mode; mark it failed.
831 error_msg = ('Required tests [%s] have not been run yet'
832 % untested_paths)
833 factory.console.error('Not running %s: %s',
834 test.path, error_msg)
835 test.update_state(status=TestState.FAILED,
836 error_msg=error_msg)
837 continue
838
Ricky Liang48e47f92014-02-26 19:31:51 +0800839 if (isinstance(test, factory.ShutdownStep) and
Ricky Liangb7eb8772014-09-15 18:05:22 +0800840 self.state_instance.get_shared_data(
841 state.POST_SHUTDOWN_TAG % test.path, optional=True)):
Ricky Liang48e47f92014-02-26 19:31:51 +0800842 # Invoking post shutdown method of shutdown test. We should retain the
843 # iterations_left and retries_left of the original test state.
844 test_state = self.state_instance.get_test_state(test.path)
845 self._run_test(test, test_state.iterations_left,
846 test_state.retries_left)
847 else:
848 # Starts a new test run; reset iterations and retries.
849 self._run_test(test, test.iterations, test.retries)
Jon Salz1acc8742012-07-17 17:45:55 +0800850
Cheng-Yi Chiangce05c002013-04-04 02:13:17 +0800851 def _run_test(self, test, iterations_left=None, retries_left=None):
Vic Yanga3cecf82014-12-26 00:44:21 -0800852 if not self._ui_initialized and not test.is_no_host():
853 self.init_ui()
Vic Yang08505c72015-01-06 17:01:53 -0800854 invoc = TestInvocation(
Hung-Te Linef7f2be2015-07-20 20:38:51 +0800855 self, test, on_completion=self.invocation_completion,
Claire Changd1961a22015-08-05 16:15:55 +0800856 on_test_failure=lambda: self.test_fail(test))
Jon Salz1acc8742012-07-17 17:45:55 +0800857 new_state = test.update_state(
Ricky Liang48e47f92014-02-26 19:31:51 +0800858 status=TestState.ACTIVE, increment_count=1, error_msg='',
859 invocation=invoc.uuid, iterations_left=iterations_left,
860 retries_left=retries_left,
861 visible=(self.visible_test == test))
Jon Salz1acc8742012-07-17 17:45:55 +0800862 invoc.count = new_state.count
863
864 self.invocations[test] = invoc
865 if self.visible_test is None and test.has_ui:
866 self.set_visible_test(test)
Vic Yang311ddb82012-09-26 12:08:28 +0800867 self.check_exclusive()
Jon Salz1acc8742012-07-17 17:45:55 +0800868 invoc.start()
Jon Salz5f2a0672012-05-22 17:14:06 +0800869
Vic Yang311ddb82012-09-26 12:08:28 +0800870 def check_exclusive(self):
Jon Salzce6a7f82013-06-10 18:22:54 +0800871 # alias since this is really long
872 EXCL_OPT = factory.FactoryTest.EXCLUSIVE_OPTIONS
873
Vic Yang311ddb82012-09-26 12:08:28 +0800874 current_exclusive_items = set([
Jon Salzce6a7f82013-06-10 18:22:54 +0800875 item for item in EXCL_OPT
Vic Yang311ddb82012-09-26 12:08:28 +0800876 if any([test.is_exclusive(item) for test in self.invocations])])
877
878 new_exclusive_items = current_exclusive_items - self.exclusive_items
Jon Salzce6a7f82013-06-10 18:22:54 +0800879 if EXCL_OPT.NETWORKING in new_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800880 logging.info('Disabling network')
881 self.connection_manager.DisableNetworking()
Jon Salzce6a7f82013-06-10 18:22:54 +0800882 if EXCL_OPT.CHARGER in new_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800883 logging.info('Stop controlling charger')
884
885 new_non_exclusive_items = self.exclusive_items - current_exclusive_items
Jon Salzce6a7f82013-06-10 18:22:54 +0800886 if EXCL_OPT.NETWORKING in new_non_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800887 logging.info('Re-enabling network')
888 self.connection_manager.EnableNetworking()
Jon Salzce6a7f82013-06-10 18:22:54 +0800889 if EXCL_OPT.CHARGER in new_non_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800890 logging.info('Start controlling charger')
891
Jon Salzce6a7f82013-06-10 18:22:54 +0800892 if self.cpufreq_manager:
893 enabled = EXCL_OPT.CPUFREQ not in current_exclusive_items
894 try:
895 self.cpufreq_manager.SetEnabled(enabled)
896 except: # pylint: disable=W0702
897 logging.exception('Unable to %s cpufreq services',
898 'enable' if enabled else 'disable')
899
Ricky Liang0f9978e2015-01-30 08:19:17 +0000900 # Only adjust charge state if not excluded
901 if (EXCL_OPT.CHARGER not in current_exclusive_items and
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800902 not sys_utils.InChroot()):
Ricky Liang0f9978e2015-01-30 08:19:17 +0000903 if self.charge_manager:
Cheng-Yi Chiangd8186952013-04-04 23:41:14 +0800904 self.charge_manager.AdjustChargeState()
905 else:
Dean Liao88b93192014-10-23 19:37:41 +0800906 self.charge()
Vic Yang311ddb82012-09-26 12:08:28 +0800907
908 self.exclusive_items = current_exclusive_items
Jon Salz5da61e62012-05-31 13:06:22 +0800909
Dean Liao88b93192014-10-23 19:37:41 +0800910 def charge(self):
911 """Charges the board.
912
913 It won't try again if last time SetChargeState raised an exception.
914 """
915 if not self._can_charge:
916 return
917
918 try:
Ricky Liang9ac35e02015-01-30 16:01:32 +0800919 if self.charge_manager:
920 self.charge_manager.StartCharging()
921 else:
Hung-Te Lin6a72c642015-12-13 22:09:09 +0800922 self.dut.power.SetChargeState(self.dut.power.ChargeState.CHARGE)
Dean Liao88b93192014-10-23 19:37:41 +0800923 except NotImplementedError:
924 logging.info('Charging is not supported')
925 self._can_charge = False
Hung-Te Lin6a72c642015-12-13 22:09:09 +0800926 except dut.DUTException:
Dean Liao88b93192014-10-23 19:37:41 +0800927 logging.exception('Unable to set charge state on this board')
928 self._can_charge = False
929
cychiang21886742012-07-05 15:16:32 +0800930 def check_for_updates(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800931 """Schedules an asynchronous check for updates if necessary."""
cychiang21886742012-07-05 15:16:32 +0800932 if not self.test_list.options.update_period_secs:
933 # Not enabled.
934 return
935
936 now = time.time()
937 if self.last_update_check and (
938 now - self.last_update_check <
939 self.test_list.options.update_period_secs):
940 # Not yet time for another check.
941 return
942
943 self.last_update_check = now
944
945 def handle_check_for_update(reached_shopfloor, md5sum, needs_update):
946 if reached_shopfloor:
947 new_update_md5sum = md5sum if needs_update else None
Hung-Te Line594e5d2015-12-16 02:36:05 +0800948 if self.dut.info.update_md5sum != new_update_md5sum:
cychiang21886742012-07-05 15:16:32 +0800949 logging.info('Received new update MD5SUM: %s', new_update_md5sum)
Hung-Te Line594e5d2015-12-16 02:36:05 +0800950 self.dut.info.Overrides('update_md5sum', new_update_md5sum)
Peter Ammon1e1ec572014-06-26 17:56:32 -0700951 self.run_enqueue(self.update_system_info)
Cheng-Yi Chiang194d3c02015-03-16 14:37:15 +0800952 else:
953 if not self._suppress_periodic_update_messages:
954 logging.warning('Suppress error messages for periodic update checking'
955 ' after the first one.')
956 self._suppress_periodic_update_messages = True
cychiang21886742012-07-05 15:16:32 +0800957
958 updater.CheckForUpdateAsync(
Ricky Liang45c73e72015-01-15 15:00:30 +0800959 handle_check_for_update,
Cheng-Yi Chiang194d3c02015-03-16 14:37:15 +0800960 self.test_list.options.shopfloor_timeout_secs,
961 self._suppress_periodic_update_messages)
cychiang21886742012-07-05 15:16:32 +0800962
Jon Salza6711d72012-07-18 14:33:03 +0800963 def cancel_pending_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800964 """Cancels any tests in the run queue."""
Jon Salza6711d72012-07-18 14:33:03 +0800965 self.run_tests([])
966
Ricky Liang4bff3e32014-02-20 18:46:11 +0800967 def restore_active_run_state(self):
968 """Restores active run id and the list of scheduled tests."""
969 self.run_id = self.state_instance.get_shared_data('run_id', optional=True)
970 self.scheduled_run_tests = self.state_instance.get_shared_data(
971 'scheduled_run_tests', optional=True)
972
973 def set_active_run_state(self):
974 """Sets active run id and the list of scheduled tests."""
975 self.run_id = str(uuid.uuid4())
976 self.scheduled_run_tests = [test.path for test in self.tests_to_run]
977 self.state_instance.set_shared_data('run_id', self.run_id)
978 self.state_instance.set_shared_data('scheduled_run_tests',
979 self.scheduled_run_tests)
980
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +0800981 def run_tests(self, subtrees, status_filter=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800982 """Runs tests under subtree.
Jon Salz258a40c2012-04-19 12:34:01 +0800983
Jon Salz0697cbf2012-07-04 15:14:04 +0800984 The tests are run in order unless one fails (then stops).
985 Backgroundable tests are run simultaneously; when a foreground test is
986 encountered, we wait for all active tests to finish before continuing.
Jon Salzb1b39092012-05-03 02:05:09 +0800987
Ricky Liang6fe218c2013-12-27 15:17:17 +0800988 Args:
989 subtrees: Node or nodes containing tests to run (may either be
990 a single test or a list). Duplicates will be ignored.
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +0800991 status_filter: List of available test states. Only run the tests which
992 states are in the list. Set to None if all test states are available.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800993 """
Hung-Te Lin410f70a2015-12-15 14:53:42 +0800994 self.dut.hooks.OnTestStart()
Vic Yang08505c72015-01-06 17:01:53 -0800995
Jon Salz0697cbf2012-07-04 15:14:04 +0800996 if type(subtrees) != list:
997 subtrees = [subtrees]
Jon Salz258a40c2012-04-19 12:34:01 +0800998
Jon Salz0697cbf2012-07-04 15:14:04 +0800999 # Nodes we've seen so far, to avoid duplicates.
1000 seen = set()
Jon Salz94eb56f2012-06-12 18:01:12 +08001001
Jon Salz0697cbf2012-07-04 15:14:04 +08001002 self.tests_to_run = deque()
1003 for subtree in subtrees:
1004 for test in subtree.walk():
1005 if test in seen:
1006 continue
1007 seen.add(test)
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001008
Jon Salz0697cbf2012-07-04 15:14:04 +08001009 if not test.is_leaf():
1010 continue
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +08001011 if (status_filter is not None and
1012 test.get_state().status not in status_filter):
Jon Salz0697cbf2012-07-04 15:14:04 +08001013 continue
1014 self.tests_to_run.append(test)
Ricky Liang4bff3e32014-02-20 18:46:11 +08001015 if subtrees:
1016 self.set_active_run_state()
Jon Salz0697cbf2012-07-04 15:14:04 +08001017 self.run_next_test()
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001018
Jon Salz0697cbf2012-07-04 15:14:04 +08001019 def reap_completed_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001020 """Removes completed tests from the set of active tests.
Jon Salz0697cbf2012-07-04 15:14:04 +08001021
1022 Also updates the visible test if it was reaped.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001023 """
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001024 test_completed = False
Jon Salz0697cbf2012-07-04 15:14:04 +08001025 for t, v in dict(self.invocations).iteritems():
1026 if v.is_completed():
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001027 test_completed = True
Jon Salz1acc8742012-07-17 17:45:55 +08001028 new_state = t.update_state(**v.update_state_on_completion)
Jon Salz0697cbf2012-07-04 15:14:04 +08001029 del self.invocations[t]
1030
Johny Lin62ed2a32015-05-13 11:57:12 +08001031 # Stop on failure if flag is true and there is no retry chances.
Chun-Ta Lin54e17e42012-09-06 22:05:13 +08001032 if (self.test_list.options.stop_on_failure and
Johny Lin62ed2a32015-05-13 11:57:12 +08001033 new_state.retries_left < 0 and
Chun-Ta Lin54e17e42012-09-06 22:05:13 +08001034 new_state.status == TestState.FAILED):
1035 # Clean all the tests to cause goofy to stop.
1036 self.tests_to_run = []
Ricky Liang45c73e72015-01-15 15:00:30 +08001037 factory.console.info('Stop on failure triggered. Empty the queue.')
Chun-Ta Lin54e17e42012-09-06 22:05:13 +08001038
Jon Salz1acc8742012-07-17 17:45:55 +08001039 if new_state.iterations_left and new_state.status == TestState.PASSED:
1040 # Play it again, Sam!
1041 self._run_test(t)
Cheng-Yi Chiangce05c002013-04-04 02:13:17 +08001042 # new_state.retries_left is obtained after update.
1043 # For retries_left == 0, test can still be run for the last time.
1044 elif (new_state.retries_left >= 0 and
1045 new_state.status == TestState.FAILED):
1046 # Still have to retry, Sam!
1047 self._run_test(t)
Jon Salz1acc8742012-07-17 17:45:55 +08001048
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001049 if test_completed:
Vic Yangf01c59f2013-04-19 17:37:56 +08001050 self.log_watcher.KickWatchThread()
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001051
Jon Salz0697cbf2012-07-04 15:14:04 +08001052 if (self.visible_test is None or
Jon Salz85a39882012-07-05 16:45:04 +08001053 self.visible_test not in self.invocations):
Jon Salz0697cbf2012-07-04 15:14:04 +08001054 self.set_visible_test(None)
1055 # Make the first running test, if any, the visible test
1056 for t in self.test_list.walk():
1057 if t in self.invocations:
1058 self.set_visible_test(t)
1059 break
1060
Jon Salz6dc031d2013-06-19 13:06:23 +08001061 def kill_active_tests(self, abort, root=None, reason=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001062 """Kills and waits for all active tests.
Jon Salz0697cbf2012-07-04 15:14:04 +08001063
Jon Salz85a39882012-07-05 16:45:04 +08001064 Args:
1065 abort: True to change state of killed tests to FAILED, False for
Jon Salz0697cbf2012-07-04 15:14:04 +08001066 UNTESTED.
Jon Salz85a39882012-07-05 16:45:04 +08001067 root: If set, only kills tests with root as an ancestor.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001068 reason: If set, the abort reason.
1069 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001070 self.reap_completed_tests()
1071 for test, invoc in self.invocations.items():
Jon Salz85a39882012-07-05 16:45:04 +08001072 if root and not test.has_ancestor(root):
1073 continue
1074
Ricky Liang45c73e72015-01-15 15:00:30 +08001075 factory.console.info('Killing active test %s...', test.path)
Jon Salz6dc031d2013-06-19 13:06:23 +08001076 invoc.abort_and_join(reason)
Ricky Liang45c73e72015-01-15 15:00:30 +08001077 factory.console.info('Killed %s', test.path)
Jon Salz1acc8742012-07-17 17:45:55 +08001078 test.update_state(**invoc.update_state_on_completion)
Jon Salz0697cbf2012-07-04 15:14:04 +08001079 del self.invocations[test]
Jon Salz1acc8742012-07-17 17:45:55 +08001080
Jon Salz0697cbf2012-07-04 15:14:04 +08001081 if not abort:
1082 test.update_state(status=TestState.UNTESTED)
1083 self.reap_completed_tests()
1084
Jon Salz6dc031d2013-06-19 13:06:23 +08001085 def stop(self, root=None, fail=False, reason=None):
1086 self.kill_active_tests(fail, root, reason)
Jon Salz85a39882012-07-05 16:45:04 +08001087 # Remove any tests in the run queue under the root.
1088 self.tests_to_run = deque([x for x in self.tests_to_run
1089 if root and not x.has_ancestor(root)])
1090 self.run_next_test()
Jon Salz0697cbf2012-07-04 15:14:04 +08001091
Jon Salz4712ac72013-02-07 17:12:05 +08001092 def clear_state(self, root=None):
Jon Salzd7550792013-07-12 05:49:27 +08001093 if root is None:
1094 root = self.test_list
Jon Salz6dc031d2013-06-19 13:06:23 +08001095 self.stop(root, reason='Clearing test state')
Jon Salz4712ac72013-02-07 17:12:05 +08001096 for f in root.walk():
1097 if f.is_leaf():
1098 f.update_state(status=TestState.UNTESTED)
1099
Jon Salz6dc031d2013-06-19 13:06:23 +08001100 def abort_active_tests(self, reason=None):
1101 self.kill_active_tests(True, reason=reason)
Jon Salz0697cbf2012-07-04 15:14:04 +08001102
1103 def main(self):
Jon Salzeff94182013-06-19 15:06:28 +08001104 syslog.openlog('goofy')
1105
Jon Salz0697cbf2012-07-04 15:14:04 +08001106 try:
Jon Salzd7550792013-07-12 05:49:27 +08001107 self.status = Status.INITIALIZING
Jon Salz0697cbf2012-07-04 15:14:04 +08001108 self.init()
1109 self.event_log.Log('goofy_init',
Ricky Liang45c73e72015-01-15 15:00:30 +08001110 success=True)
Jon Salz0697cbf2012-07-04 15:14:04 +08001111 except:
1112 if self.event_log:
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001113 try:
Jon Salz0697cbf2012-07-04 15:14:04 +08001114 self.event_log.Log('goofy_init',
Ricky Liang45c73e72015-01-15 15:00:30 +08001115 success=False,
1116 trace=traceback.format_exc())
Jon Salz0697cbf2012-07-04 15:14:04 +08001117 except: # pylint: disable=W0702
1118 pass
1119 raise
1120
Jon Salzd7550792013-07-12 05:49:27 +08001121 self.status = Status.RUNNING
Jon Salzeff94182013-06-19 15:06:28 +08001122 syslog.syslog('Goofy (factory test harness) starting')
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001123 syslog.syslog('Boot sequence = %d' % GetBootSequence())
Jon Salz0697cbf2012-07-04 15:14:04 +08001124 self.run()
1125
1126 def update_system_info(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001127 """Updates system info."""
Hung-Te Line594e5d2015-12-16 02:36:05 +08001128 info = self.dut.info.GetAll()
1129 self.state_instance.set_shared_data('system_info', info)
Jon Salz0697cbf2012-07-04 15:14:04 +08001130 self.event_client.post_event(Event(Event.Type.SYSTEM_INFO,
Hung-Te Line594e5d2015-12-16 02:36:05 +08001131 system_info=info))
1132 logging.info('System info: %r', info)
Jon Salz0697cbf2012-07-04 15:14:04 +08001133
Jon Salzeb42f0d2012-07-27 19:14:04 +08001134 def update_factory(self, auto_run_on_restart=False, post_update_hook=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001135 """Commences updating factory software.
Jon Salzeb42f0d2012-07-27 19:14:04 +08001136
1137 Args:
1138 auto_run_on_restart: Auto-run when the machine comes back up.
1139 post_update_hook: Code to call after update but immediately before
1140 restart.
1141
1142 Returns:
1143 Never if the update was successful (we just reboot).
1144 False if the update was unnecessary (no update available).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001145 """
Jon Salz6dc031d2013-06-19 13:06:23 +08001146 self.kill_active_tests(False, reason='Factory software update')
Jon Salza6711d72012-07-18 14:33:03 +08001147 self.cancel_pending_tests()
Jon Salz0697cbf2012-07-04 15:14:04 +08001148
Jon Salz5c344f62012-07-13 14:31:16 +08001149 def pre_update_hook():
1150 if auto_run_on_restart:
1151 self.state_instance.set_shared_data('tests_after_shutdown',
1152 FORCE_AUTO_RUN)
1153 self.state_instance.close()
1154
Jon Salzeb42f0d2012-07-27 19:14:04 +08001155 if updater.TryUpdate(pre_update_hook=pre_update_hook):
1156 if post_update_hook:
1157 post_update_hook()
1158 self.env.shutdown('reboot')
Jon Salz0697cbf2012-07-04 15:14:04 +08001159
Ricky Liang8fecf412014-05-22 10:56:14 +08001160 def handle_sigint(self, dummy_signum, dummy_frame): # pylint: disable=W0613
Jon Salz77c151e2012-08-28 07:20:37 +08001161 logging.error('Received SIGINT')
Peter Ammon1e1ec572014-06-26 17:56:32 -07001162 self.run_enqueue(None)
Jon Salz77c151e2012-08-28 07:20:37 +08001163 raise KeyboardInterrupt()
1164
Ricky Liang8fecf412014-05-22 10:56:14 +08001165 def handle_sigterm(self, dummy_signum, dummy_frame): # pylint: disable=W0613
1166 logging.error('Received SIGTERM')
Hung-Te Lin94ca4742014-07-09 20:13:50 +08001167 self.env.terminate()
1168 self.run_queue.put(None)
Ricky Liang8fecf412014-05-22 10:56:14 +08001169 raise RuntimeError('Received SIGTERM')
1170
Jon Salze12c2b32013-06-25 16:24:34 +08001171 def find_kcrashes(self):
1172 """Finds kcrash files, logs them, and marks them as seen."""
1173 seen_crashes = set(
1174 self.state_instance.get_shared_data('seen_crashes', optional=True)
1175 or [])
1176
1177 for path in glob.glob('/var/spool/crash/*'):
1178 if not os.path.isfile(path):
1179 continue
1180 if path in seen_crashes:
1181 continue
1182 try:
1183 stat = os.stat(path)
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001184 mtime = time_utils.TimeString(stat.st_mtime)
Jon Salze12c2b32013-06-25 16:24:34 +08001185 logging.info(
1186 'Found new crash file %s (%d bytes at %s)',
1187 path, stat.st_size, mtime)
1188 extra_log_args = {}
1189
1190 try:
1191 _, ext = os.path.splitext(path)
1192 if ext in ['.kcrash', '.meta']:
1193 ext = ext.replace('.', '')
1194 with open(path) as f:
1195 data = f.read(MAX_CRASH_FILE_SIZE)
1196 tell = f.tell()
1197 logging.info(
1198 'Contents of %s%s:%s',
1199 path,
1200 ('' if tell == stat.st_size
1201 else '(truncated to %d bytes)' % MAX_CRASH_FILE_SIZE),
1202 ('\n' + data).replace('\n', '\n ' + ext + '> '))
1203 extra_log_args['data'] = data
1204
1205 # Copy to /var/factory/kcrash for posterity
1206 kcrash_dir = factory.get_factory_root('kcrash')
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001207 file_utils.TryMakeDirs(kcrash_dir)
Jon Salze12c2b32013-06-25 16:24:34 +08001208 shutil.copy(path, kcrash_dir)
1209 logging.info('Copied to %s',
1210 os.path.join(kcrash_dir, os.path.basename(path)))
1211 finally:
1212 # Even if something goes wrong with the above, still try to
1213 # log to event log
1214 self.event_log.Log('crash_file',
1215 path=path, size=stat.st_size, mtime=mtime,
1216 **extra_log_args)
1217 except: # pylint: disable=W0702
1218 logging.exception('Unable to handle crash files %s', path)
1219 seen_crashes.add(path)
1220
1221 self.state_instance.set_shared_data('seen_crashes', list(seen_crashes))
1222
Jon Salz128b0932013-07-03 16:55:26 +08001223 def GetTestList(self, test_list_id):
1224 """Returns the test list with the given ID.
1225
1226 Raises:
1227 TestListError: The test list ID is not valid.
1228 """
1229 try:
1230 return self.test_lists[test_list_id]
1231 except KeyError:
1232 raise test_lists.TestListError(
1233 '%r is not a valid test list ID (available IDs are [%s])' % (
1234 test_list_id, ', '.join(sorted(self.test_lists.keys()))))
1235
1236 def InitTestLists(self):
1237 """Reads in all test lists and sets the active test list."""
Ricky Liang27051552014-05-04 14:22:26 +08001238 self.test_lists = test_lists.BuildAllTestLists(
1239 force_generic=(self.options.automation_mode is not None))
Jon Salzd7550792013-07-12 05:49:27 +08001240 logging.info('Loaded test lists: [%s]',
1241 test_lists.DescribeTestLists(self.test_lists))
Jon Salz128b0932013-07-03 16:55:26 +08001242
1243 if not self.options.test_list:
1244 self.options.test_list = test_lists.GetActiveTestListId()
1245
1246 if os.sep in self.options.test_list:
1247 # It's a path pointing to an old-style test list; use it.
1248 self.test_list = factory.read_test_list(self.options.test_list)
1249 else:
1250 self.test_list = self.GetTestList(self.options.test_list)
1251
1252 logging.info('Active test list: %s', self.test_list.test_list_id)
1253
1254 if isinstance(self.test_list, test_lists.OldStyleTestList):
1255 # Actually load it in. (See OldStyleTestList for an explanation
1256 # of why this is necessary.)
1257 self.test_list = self.test_list.Load()
1258
1259 self.test_list.state_instance = self.state_instance
1260
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001261 def init_hooks(self):
1262 """Initializes hooks.
1263
1264 Must run after self.test_list ready.
1265 """
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001266 module, cls = self.test_list.options.hooks_class.rsplit('.', 1)
1267 self.hooks = getattr(__import__(module, fromlist=[cls]), cls)()
1268 assert isinstance(self.hooks, factory.Hooks), (
Ricky Liang45c73e72015-01-15 15:00:30 +08001269 'hooks should be of type Hooks but is %r' % type(self.hooks))
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001270 self.hooks.test_list = self.test_list
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001271 self.hooks.OnCreatedTestList()
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001272
Vic Yanga3cecf82014-12-26 00:44:21 -08001273 def init_ui(self):
1274 """Initialize UI."""
1275 self._ui_initialized = True
1276 if self.options.ui == 'chrome':
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001277 if self.options.monolithic:
Hung-Te Lin7bd55312014-12-30 16:43:36 +08001278 self.env.launch_chrome()
1279 else:
1280 # The presenter is responsible for launching Chrome. Let's just
1281 # wait here.
1282 self.env.controller_ready_for_ui()
Vic Yanga3cecf82014-12-26 00:44:21 -08001283 logging.info('Waiting for a web socket connection')
1284 self.web_socket_manager.wait()
1285
1286 # Wait for the test widget size to be set; this is done in
1287 # an asynchronous RPC so there is a small chance that the
1288 # web socket might be opened first.
1289 for _ in range(100): # 10 s
1290 try:
1291 if self.state_instance.get_shared_data('test_widget_size'):
1292 break
1293 except KeyError:
1294 pass # Retry
1295 time.sleep(0.1) # 100 ms
1296 else:
1297 logging.warn('Never received test_widget_size from UI')
1298
Hung-Te Lin7bd55312014-12-30 16:43:36 +08001299 logging.info('Waiting for a web socket connection')
1300 self.web_socket_manager.wait()
1301
Jon Salz0697cbf2012-07-04 15:14:04 +08001302 def init(self, args=None, env=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001303 """Initializes Goofy.
Jon Salz0697cbf2012-07-04 15:14:04 +08001304
1305 Args:
1306 args: A list of command-line arguments. Uses sys.argv if
1307 args is None.
1308 env: An Environment instance to use (or None to choose
1309 FakeChrootEnvironment or DUTEnvironment as appropriate).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001310 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001311 parser = OptionParser()
1312 parser.add_option('-v', '--verbose', dest='verbose',
Jon Salz8fa8e832012-07-13 19:04:09 +08001313 action='store_true',
1314 help='Enable debug logging')
Jon Salz0697cbf2012-07-04 15:14:04 +08001315 parser.add_option('--print_test_list', dest='print_test_list',
Jon Salz8fa8e832012-07-13 19:04:09 +08001316 metavar='FILE',
1317 help='Read and print test list FILE, and exit')
Jon Salz0697cbf2012-07-04 15:14:04 +08001318 parser.add_option('--restart', dest='restart',
Jon Salz8fa8e832012-07-13 19:04:09 +08001319 action='store_true',
1320 help='Clear all test state')
Jon Salz0697cbf2012-07-04 15:14:04 +08001321 parser.add_option('--ui', dest='ui', type='choice',
Jon Salz7b5482e2014-08-04 17:48:41 +08001322 choices=['none', 'chrome'],
Jon Salz2f881df2013-02-01 17:00:35 +08001323 default='chrome',
Jon Salz8fa8e832012-07-13 19:04:09 +08001324 help='UI to use')
Jon Salz0697cbf2012-07-04 15:14:04 +08001325 parser.add_option('--ui_scale_factor', dest='ui_scale_factor',
Jon Salz8fa8e832012-07-13 19:04:09 +08001326 type='int', default=1,
1327 help=('Factor by which to scale UI '
1328 '(Chrome UI only)'))
Jon Salz0697cbf2012-07-04 15:14:04 +08001329 parser.add_option('--test_list', dest='test_list',
Jon Salz8fa8e832012-07-13 19:04:09 +08001330 metavar='FILE',
1331 help='Use FILE as test list')
Jon Salzc79a9982012-08-30 04:42:01 +08001332 parser.add_option('--dummy_shopfloor', action='store_true',
1333 help='Use a dummy shopfloor server')
Hung-Te Lincc41d2a2014-10-29 13:35:20 +08001334 parser.add_option('--dummy_connection_manager', action='store_true',
1335 help='Use a dummy connection manager')
Ricky Liang6fe218c2013-12-27 15:17:17 +08001336 parser.add_option('--automation-mode',
1337 choices=[m.lower() for m in AutomationMode],
Ricky Liang45c73e72015-01-15 15:00:30 +08001338 default='none', help='Factory test automation mode.')
Ricky Liang117484a2014-04-14 11:14:41 +08001339 parser.add_option('--no-auto-run-on-start', dest='auto_run_on_start',
1340 action='store_false', default=True,
1341 help=('do not automatically run the test list on goofy '
1342 'start; this is only valid when factory test '
1343 'automation is enabled'))
Chun-Ta Lina8dd3172014-11-26 16:15:13 +08001344 parser.add_option('--handshake_timeout', dest='handshake_timeout',
1345 type='float', default=0.3,
1346 help=('RPC timeout when doing handshake between device '
1347 'and presenter.'))
Vic Yang7d693c42014-09-14 09:52:39 +08001348 parser.add_option('--standalone', dest='standalone',
1349 action='store_true', default=False,
1350 help=('Assume the presenter is running on the same '
1351 'machines.'))
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001352 parser.add_option('--monolithic', dest='monolithic',
1353 action='store_true', default=False,
1354 help='Run in monolithic mode (without presenter)')
Jon Salz0697cbf2012-07-04 15:14:04 +08001355 (self.options, self.args) = parser.parse_args(args)
1356
Hung-Te Lina846f602014-07-04 20:32:22 +08001357 signal.signal(signal.SIGINT, self.handle_sigint)
1358 # TODO(hungte) SIGTERM does not work properly without Telemetry and should
1359 # be fixed.
Hung-Te Lina846f602014-07-04 20:32:22 +08001360
Jon Salz46b89562012-07-05 11:49:22 +08001361 # Make sure factory directories exist.
1362 factory.get_log_root()
1363 factory.get_state_root()
1364 factory.get_test_data_root()
1365
Jon Salz0697cbf2012-07-04 15:14:04 +08001366 global _inited_logging # pylint: disable=W0603
1367 if not _inited_logging:
1368 factory.init_logging('goofy', verbose=self.options.verbose)
1369 _inited_logging = True
Jon Salz8fa8e832012-07-13 19:04:09 +08001370
Jon Salz0f996602012-10-03 15:26:48 +08001371 if self.options.print_test_list:
Joel Kitchingb85ed7f2014-10-08 18:24:39 +08001372 print(factory.read_test_list(
1373 self.options.print_test_list).__repr__(recursive=True))
Jon Salz0f996602012-10-03 15:26:48 +08001374 sys.exit(0)
1375
Jon Salzee85d522012-07-17 14:34:46 +08001376 event_log.IncrementBootSequence()
Jon Salzd15bbcf2013-05-21 17:33:57 +08001377 # Don't defer logging the initial event, so we can make sure
1378 # that device_id, reimage_id, etc. are all set up.
1379 self.event_log = EventLog('goofy', defer=False)
Jon Salz0697cbf2012-07-04 15:14:04 +08001380
Jon Salz0697cbf2012-07-04 15:14:04 +08001381 if env:
1382 self.env = env
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001383 elif sys_utils.InChroot():
Jon Salz0697cbf2012-07-04 15:14:04 +08001384 self.env = test_environment.FakeChrootEnvironment()
1385 logging.warn(
Ricky Liang45c73e72015-01-15 15:00:30 +08001386 'Using chroot environment: will not actually run autotests')
Hung-Te Lina846f602014-07-04 20:32:22 +08001387 elif self.options.ui == 'chrome':
Ricky Liang09d66d82014-09-25 11:20:54 +08001388 self.env = test_environment.DUTEnvironment()
Jon Salz0697cbf2012-07-04 15:14:04 +08001389 self.env.goofy = self
Vic Yanga4931152014-08-11 16:36:24 -07001390 # web_socket_manager will be initialized later
1391 # pylint: disable=W0108
1392 self.env.has_sockets = lambda: self.web_socket_manager.has_sockets()
Jon Salz0697cbf2012-07-04 15:14:04 +08001393
1394 if self.options.restart:
1395 state.clear_state()
1396
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001397 if self.options.ui_scale_factor != 1 and sys_utils.InQEMU():
Jon Salz0697cbf2012-07-04 15:14:04 +08001398 logging.warn(
Ricky Liang45c73e72015-01-15 15:00:30 +08001399 'In QEMU; ignoring ui_scale_factor argument')
Jon Salz0697cbf2012-07-04 15:14:04 +08001400 self.options.ui_scale_factor = 1
1401
1402 logging.info('Started')
1403
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001404 if not self.options.monolithic:
Hung-Te Lin7bd55312014-12-30 16:43:36 +08001405 self.link_manager = PresenterLinkManager(
1406 check_interval=1,
1407 handshake_timeout=self.options.handshake_timeout,
1408 standalone=self.options.standalone)
Peter Ammon1e1ec572014-06-26 17:56:32 -07001409
Jon Salz0697cbf2012-07-04 15:14:04 +08001410 self.start_state_server()
1411 self.state_instance.set_shared_data('hwid_cfg', get_hwid_cfg())
1412 self.state_instance.set_shared_data('ui_scale_factor',
Ricky Liang09216dc2013-02-22 17:26:45 +08001413 self.options.ui_scale_factor)
Jon Salz0697cbf2012-07-04 15:14:04 +08001414 self.last_shutdown_time = (
Ricky Liang45c73e72015-01-15 15:00:30 +08001415 self.state_instance.get_shared_data('shutdown_time', optional=True))
Jon Salz0697cbf2012-07-04 15:14:04 +08001416 self.state_instance.del_shared_data('shutdown_time', optional=True)
Jon Salzb19ea072013-02-07 16:35:00 +08001417 self.state_instance.del_shared_data('startup_error', optional=True)
Jon Salz0697cbf2012-07-04 15:14:04 +08001418
Ricky Liang6fe218c2013-12-27 15:17:17 +08001419 self.options.automation_mode = ParseAutomationMode(
1420 self.options.automation_mode)
1421 self.state_instance.set_shared_data('automation_mode',
1422 self.options.automation_mode)
1423 self.state_instance.set_shared_data(
1424 'automation_mode_prompt',
1425 AutomationModePrompt[self.options.automation_mode])
1426
Jon Salz128b0932013-07-03 16:55:26 +08001427 try:
1428 self.InitTestLists()
1429 except: # pylint: disable=W0702
1430 logging.exception('Unable to initialize test lists')
1431 self.state_instance.set_shared_data(
1432 'startup_error',
1433 'Unable to initialize test lists\n%s' % (
1434 traceback.format_exc()))
Jon Salzb19ea072013-02-07 16:35:00 +08001435 if self.options.ui == 'chrome':
1436 # Create an empty test list with default options so that the rest of
1437 # startup can proceed.
1438 self.test_list = factory.FactoryTestList(
1439 [], self.state_instance, factory.Options())
1440 else:
1441 # Bail with an error; no point in starting up.
1442 sys.exit('No valid test list; exiting.')
1443
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001444 self.init_hooks()
1445
Jon Salz822838b2013-03-25 17:32:33 +08001446 if self.test_list.options.clear_state_on_start:
1447 self.state_instance.clear_test_state()
1448
Jon Salz670ce062014-05-16 15:53:50 +08001449 # If the phase is invalid, this will raise a ValueError.
1450 phase.SetPersistentPhase(self.test_list.options.phase)
1451
Dean Liao85ca86f2014-11-03 12:28:08 +08001452 # For netboot firmware, mainfw_type should be 'netboot'.
Hung-Te Line594e5d2015-12-16 02:36:05 +08001453 if (self.dut.info.mainfw_type != 'nonchrome' and
1454 self.dut.info.firmware_version is None):
Ricky Liang45c73e72015-01-15 15:00:30 +08001455 self.state_instance.set_shared_data(
1456 'startup_error',
Vic Yang9bd4f772013-06-04 17:34:00 +08001457 'Netboot firmware detected\n'
1458 'Connect Ethernet and reboot to re-image.\n'
1459 u'侦测到网路开机固件\n'
1460 u'请连接乙太网并重启')
1461
Jon Salz0697cbf2012-07-04 15:14:04 +08001462 if not self.state_instance.has_shared_data('ui_lang'):
1463 self.state_instance.set_shared_data('ui_lang',
Ricky Liang45c73e72015-01-15 15:00:30 +08001464 self.test_list.options.ui_lang)
Jon Salz0697cbf2012-07-04 15:14:04 +08001465 self.state_instance.set_shared_data(
Ricky Liang45c73e72015-01-15 15:00:30 +08001466 'test_list_options',
1467 self.test_list.options.__dict__)
Jon Salz0697cbf2012-07-04 15:14:04 +08001468 self.state_instance.test_list = self.test_list
1469
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001470 self.check_log_rotation()
Jon Salz83ef34b2012-11-01 19:46:35 +08001471
Jon Salz23926422012-09-01 03:38:13 +08001472 if self.options.dummy_shopfloor:
Ricky Liang45c73e72015-01-15 15:00:30 +08001473 os.environ[shopfloor.SHOPFLOOR_SERVER_ENV_VAR_NAME] = (
1474 'http://%s:%d/' %
Joel Kitchingb85ed7f2014-10-08 18:24:39 +08001475 (net_utils.LOCALHOST, shopfloor.DEFAULT_SERVER_PORT))
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001476 self.dummy_shopfloor = process_utils.Spawn(
Jon Salz23926422012-09-01 03:38:13 +08001477 [os.path.join(factory.FACTORY_PATH, 'bin', 'shopfloor_server'),
1478 '--dummy'])
1479 elif self.test_list.options.shopfloor_server_url:
1480 shopfloor.set_server_url(self.test_list.options.shopfloor_server_url)
Jon Salz2bf2f6b2013-03-28 18:49:26 +08001481 shopfloor.set_enabled(True)
Jon Salz23926422012-09-01 03:38:13 +08001482
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001483 if self.test_list.options.time_sanitizer and not sys_utils.InChroot():
Jon Salz8fa8e832012-07-13 19:04:09 +08001484 self.time_sanitizer = time_sanitizer.TimeSanitizer(
Ricky Liang45c73e72015-01-15 15:00:30 +08001485 base_time=time_sanitizer.GetBaseTimeFromFile(
1486 # lsb-factory is written by the factory install shim during
1487 # installation, so it should have a good time obtained from
1488 # the mini-Omaha server. If it's not available, we'll use
1489 # /etc/lsb-factory (which will be much older, but reasonably
1490 # sane) and rely on a shopfloor sync to set a more accurate
1491 # time.
1492 '/usr/local/etc/lsb-factory',
1493 '/etc/lsb-release'))
Jon Salz8fa8e832012-07-13 19:04:09 +08001494 self.time_sanitizer.RunOnce()
1495
Vic Yangd8990da2013-06-27 16:57:43 +08001496 if self.test_list.options.check_cpu_usage_period_secs:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001497 self.cpu_usage_watcher = process_utils.Spawn(
Ricky Liang45c73e72015-01-15 15:00:30 +08001498 ['py/tools/cpu_usage_monitor.py', '-p',
1499 str(self.test_list.options.check_cpu_usage_period_secs)],
Vic Yangd8990da2013-06-27 16:57:43 +08001500 cwd=factory.FACTORY_PATH)
1501
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001502 # Enable thermal monitor
1503 if self.test_list.options.thermal_monitor_period_secs > 0:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001504 self.cpu_usage_watcher = process_utils.Spawn(
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001505 ['py/tools/thermal_monitor.py',
1506 '-p', str(self.test_list.options.thermal_monitor_period_secs),
1507 '-d', str(self.test_list.options.thermal_monitor_delta)],
1508 cwd=factory.FACTORY_PATH)
1509
Jon Salz0697cbf2012-07-04 15:14:04 +08001510 self.init_states()
1511 self.start_event_server()
Wei-Ning Huang38b75f02015-02-25 18:25:14 +08001512 self.start_terminal_server()
Hung-Te Lincc41d2a2014-10-29 13:35:20 +08001513
1514 if self.options.dummy_connection_manager:
1515 # Override network manager creation to dummy implmenetation.
1516 logging.info('Using dummy network manager (--dummy_connection_manager).')
1517 self.connection_manager = connection_manager.DummyConnectionManager()
1518 else:
1519 self.connection_manager = self.env.create_connection_manager(
1520 self.test_list.options.wlans,
Mao Huang4340c632015-04-14 14:35:22 +08001521 self.test_list.options.scan_wifi_period_secs,
1522 self.test_list.options.override_blacklisted_network_devices)
Hung-Te Lincc41d2a2014-10-29 13:35:20 +08001523
Jon Salz0697cbf2012-07-04 15:14:04 +08001524 # Note that we create a log watcher even if
1525 # sync_event_log_period_secs isn't set (no background
1526 # syncing), since we may use it to flush event logs as well.
1527 self.log_watcher = EventLogWatcher(
Ricky Liang45c73e72015-01-15 15:00:30 +08001528 self.test_list.options.sync_event_log_period_secs,
1529 event_log_db_file=None,
1530 handle_event_logs_callback=self.handle_event_logs)
Jon Salz0697cbf2012-07-04 15:14:04 +08001531 if self.test_list.options.sync_event_log_period_secs:
1532 self.log_watcher.StartWatchThread()
1533
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001534 # Creates a system log manager to scan logs periocially.
1535 # A scan includes clearing logs and optionally syncing logs if
1536 # enable_syng_log is True. We kick it to sync logs.
1537 self.system_log_manager = SystemLogManager(
Ricky Liang45c73e72015-01-15 15:00:30 +08001538 sync_log_paths=self.test_list.options.sync_log_paths,
1539 sync_log_period_secs=self.test_list.options.sync_log_period_secs,
1540 scan_log_period_secs=self.test_list.options.scan_log_period_secs,
1541 clear_log_paths=self.test_list.options.clear_log_paths,
1542 clear_log_excluded_paths=self.test_list.options.clear_log_excluded_paths)
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001543 self.system_log_manager.Start()
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +08001544
Jon Salz0697cbf2012-07-04 15:14:04 +08001545 self.update_system_info()
1546
Vic Yang4953fc12012-07-26 16:19:53 +08001547 assert ((self.test_list.options.min_charge_pct is None) ==
1548 (self.test_list.options.max_charge_pct is None))
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001549 if sys_utils.InChroot():
Vic Yange83d9a12013-04-19 20:00:20 +08001550 logging.info('In chroot, ignoring charge manager and charge state')
Ricky Liangc392a1c2014-06-20 18:24:59 +08001551 elif (self.test_list.options.enable_charge_manager and
1552 self.test_list.options.min_charge_pct is not None):
Vic Yang4953fc12012-07-26 16:19:53 +08001553 self.charge_manager = ChargeManager(self.test_list.options.min_charge_pct,
1554 self.test_list.options.max_charge_pct)
Hung-Te Linc17b3d82015-12-15 15:26:08 +08001555 self.dut.status.Overrides('charge_manager', self.charge_manager)
Cheng-Yi Chiangd8186952013-04-04 23:41:14 +08001556 else:
1557 # Goofy should set charger state to charge if charge_manager is disabled.
Dean Liao88b93192014-10-23 19:37:41 +08001558 self.charge()
Vic Yang4953fc12012-07-26 16:19:53 +08001559
Vic Yang6cee2472014-10-22 17:18:52 -07001560 if CoreDumpManager.CoreDumpEnabled():
1561 self.core_dump_manager = CoreDumpManager(
1562 self.test_list.options.core_dump_watchlist)
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001563
Jon Salz0697cbf2012-07-04 15:14:04 +08001564 os.environ['CROS_FACTORY'] = '1'
1565 os.environ['CROS_DISABLE_SITE_SYSINFO'] = '1'
1566
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001567 if not sys_utils.InChroot() and self.test_list.options.use_cpufreq_manager:
Ricky Liangecddbd42014-07-24 11:32:10 +08001568 logging.info('Enabling CPU frequency manager')
Jon Salzddf0d052013-06-18 12:52:44 +08001569 self.cpufreq_manager = CpufreqManager(event_log=self.event_log)
Jon Salzce6a7f82013-06-10 18:22:54 +08001570
Justin Chuang31b02432013-06-27 15:16:51 +08001571 # Startup hooks may want to skip some tests.
1572 self.update_skipped_tests()
Jon Salz416f9cc2013-05-10 18:32:50 +08001573
Jon Salze12c2b32013-06-25 16:24:34 +08001574 self.find_kcrashes()
1575
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001576 # Should not move earlier.
1577 self.hooks.OnStartup()
1578
Ricky Liang36512a32014-07-25 11:47:04 +08001579 # Only after this point the Goofy backend is ready for UI connection.
1580 self.ready_for_ui_connection = True
1581
Ricky Liang650f6bf2012-09-28 13:22:54 +08001582 # Create download path for autotest beforehand or autotests run at
1583 # the same time might fail due to race condition.
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001584 if not sys_utils.InChroot():
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001585 file_utils.TryMakeDirs(os.path.join('/usr/local/autotest', 'tests',
1586 'download'))
Ricky Liang650f6bf2012-09-28 13:22:54 +08001587
Jon Salz0697cbf2012-07-04 15:14:04 +08001588 def state_change_callback(test, test_state):
1589 self.event_client.post_event(
Ricky Liang4bff3e32014-02-20 18:46:11 +08001590 Event(Event.Type.STATE_CHANGE, path=test.path, state=test_state))
Jon Salz0697cbf2012-07-04 15:14:04 +08001591 self.test_list.state_change_callback = state_change_callback
Jon Salz73e0fd02012-04-04 11:46:38 +08001592
Vic Yange2c76a82014-10-30 12:48:19 -07001593 self.autotest_prespawner = prespawner.AutotestPrespawner()
1594 self.autotest_prespawner.start()
1595
1596 self.pytest_prespawner = prespawner.PytestPrespawner()
1597 self.pytest_prespawner.start()
Jon Salza6711d72012-07-18 14:33:03 +08001598
Ricky Liang48e47f92014-02-26 19:31:51 +08001599 tests_after_shutdown = self.state_instance.get_shared_data(
1600 'tests_after_shutdown', optional=True)
Jon Salz57717ca2012-04-04 16:47:25 +08001601
Jon Salz5c344f62012-07-13 14:31:16 +08001602 force_auto_run = (tests_after_shutdown == FORCE_AUTO_RUN)
1603 if not force_auto_run and tests_after_shutdown is not None:
Ricky Liang48e47f92014-02-26 19:31:51 +08001604 logging.info('Resuming tests after shutdown: %s', tests_after_shutdown)
Jon Salz0697cbf2012-07-04 15:14:04 +08001605 self.tests_to_run.extend(
Ricky Liang4bff3e32014-02-20 18:46:11 +08001606 self.test_list.lookup_path(t) for t in tests_after_shutdown)
Peter Ammon1e1ec572014-06-26 17:56:32 -07001607 self.run_enqueue(self.run_next_test)
Jon Salz0697cbf2012-07-04 15:14:04 +08001608 else:
Jon Salz5c344f62012-07-13 14:31:16 +08001609 if force_auto_run or self.test_list.options.auto_run_on_start:
Ricky Liang117484a2014-04-14 11:14:41 +08001610 # If automation mode is enabled, allow suppress auto_run_on_start.
1611 if (self.options.automation_mode == 'NONE' or
1612 self.options.auto_run_on_start):
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +08001613 status_filter = [TestState.UNTESTED]
1614 if self.test_list.options.retry_failed_on_start:
1615 status_filter.append(TestState.FAILED)
1616 self.run_enqueue(lambda: self.run_tests(self.test_list, status_filter))
Jon Salz5c344f62012-07-13 14:31:16 +08001617 self.state_instance.set_shared_data('tests_after_shutdown', None)
Ricky Liang4bff3e32014-02-20 18:46:11 +08001618 self.restore_active_run_state()
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001619
Hung-Te Lin410f70a2015-12-15 14:53:42 +08001620 self.dut.hooks.OnTestStart()
Vic Yang08505c72015-01-06 17:01:53 -08001621
Dean Liao592e4d52013-01-10 20:06:39 +08001622 self.may_disable_cros_shortcut_keys()
1623
1624 def may_disable_cros_shortcut_keys(self):
1625 test_options = self.test_list.options
1626 if test_options.disable_cros_shortcut_keys:
1627 logging.info('Filter ChromeOS shortcut keys.')
1628 self.key_filter = KeyFilter(
1629 unmap_caps_lock=test_options.disable_caps_lock,
1630 caps_lock_keycode=test_options.caps_lock_keycode)
1631 self.key_filter.Start()
1632
Jon Salz0e6532d2012-10-25 16:30:11 +08001633 def _should_sync_time(self, foreground=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001634 """Returns True if we should attempt syncing time with shopfloor.
Jon Salz0e6532d2012-10-25 16:30:11 +08001635
1636 Args:
1637 foreground: If True, synchronizes even if background syncing
1638 is disabled (e.g., in explicit sync requests from the
1639 SyncShopfloor test).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001640 """
Jon Salz0e6532d2012-10-25 16:30:11 +08001641 return ((foreground or
1642 self.test_list.options.sync_time_period_secs) and
Jon Salz54882d02012-08-31 01:57:54 +08001643 self.time_sanitizer and
1644 (not self.time_synced) and
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001645 (not sys_utils.InChroot()))
Jon Salz54882d02012-08-31 01:57:54 +08001646
Jon Salz0e6532d2012-10-25 16:30:11 +08001647 def sync_time_with_shopfloor_server(self, foreground=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001648 """Syncs time with shopfloor server, if not yet synced.
Jon Salz54882d02012-08-31 01:57:54 +08001649
Jon Salz0e6532d2012-10-25 16:30:11 +08001650 Args:
1651 foreground: If True, synchronizes even if background syncing
1652 is disabled (e.g., in explicit sync requests from the
1653 SyncShopfloor test).
1654
Jon Salz54882d02012-08-31 01:57:54 +08001655 Returns:
1656 False if no time sanitizer is available, or True if this sync (or a
1657 previous sync) succeeded.
1658
1659 Raises:
1660 Exception if unable to contact the shopfloor server.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001661 """
Jon Salz0e6532d2012-10-25 16:30:11 +08001662 if self._should_sync_time(foreground):
Jon Salz54882d02012-08-31 01:57:54 +08001663 self.time_sanitizer.SyncWithShopfloor()
1664 self.time_synced = True
1665 return self.time_synced
1666
Jon Salzb92c5112012-09-21 15:40:11 +08001667 def log_disk_space_stats(self):
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001668 if (sys_utils.InChroot() or
Jon Salz18e0e022013-06-11 17:13:39 +08001669 not self.test_list.options.log_disk_space_period_secs):
Jon Salzb92c5112012-09-21 15:40:11 +08001670 return
1671
1672 now = time.time()
1673 if (self.last_log_disk_space_time and
1674 now - self.last_log_disk_space_time <
1675 self.test_list.options.log_disk_space_period_secs):
1676 return
1677 self.last_log_disk_space_time = now
1678
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001679 # Upload event if stateful partition usage is above threshold.
1680 # Stateful partition is mounted on /usr/local, while
1681 # encrypted stateful partition is mounted on /var.
1682 # If there are too much logs in the factory process,
1683 # these two partitions might get full.
Jon Salzb92c5112012-09-21 15:40:11 +08001684 try:
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001685 vfs_infos = disk_space.GetAllVFSInfo()
1686 stateful_info, encrypted_info = None, None
1687 for vfs_info in vfs_infos.values():
1688 if '/usr/local' in vfs_info.mount_points:
1689 stateful_info = vfs_info
1690 if '/var' in vfs_info.mount_points:
1691 encrypted_info = vfs_info
1692
1693 stateful = disk_space.GetPartitionUsage(stateful_info)
1694 encrypted = disk_space.GetPartitionUsage(encrypted_info)
1695
Ricky Liang45c73e72015-01-15 15:00:30 +08001696 above_threshold = (
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001697 self.test_list.options.stateful_usage_threshold and
1698 max(stateful.bytes_used_pct,
1699 stateful.inodes_used_pct,
1700 encrypted.bytes_used_pct,
1701 encrypted.inodes_used_pct) >
Ricky Liang45c73e72015-01-15 15:00:30 +08001702 self.test_list.options.stateful_usage_threshold)
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001703
1704 if above_threshold:
1705 self.event_log.Log('stateful_partition_usage',
Ricky Liang45c73e72015-01-15 15:00:30 +08001706 partitions={
1707 'stateful': {
1708 'bytes_used_pct': FloatDigit(stateful.bytes_used_pct, 2),
1709 'inodes_used_pct': FloatDigit(stateful.inodes_used_pct, 2)},
1710 'encrypted_stateful': {
1711 'bytes_used_pct': FloatDigit(encrypted.bytes_used_pct, 2),
1712 'inodes_used_pct': FloatDigit(encrypted.inodes_used_pct, 2)}
1713 })
Cheng-Yi Chiang1b722322015-03-16 20:07:03 +08001714 self.log_watcher.KickWatchThread()
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001715 if (not sys_utils.InChroot() and
Cheng-Yi Chiang00798e72013-06-20 18:16:39 +08001716 self.test_list.options.stateful_usage_above_threshold_action):
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001717 process_utils.Spawn(
1718 self.test_list.options.stateful_usage_above_threshold_action,
1719 call=True)
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001720
1721 message = disk_space.FormatSpaceUsedAll(vfs_infos)
Jon Salz3c493bb2013-02-07 17:24:58 +08001722 if message != self.last_log_disk_space_message:
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001723 if above_threshold:
1724 logging.warning(message)
1725 else:
1726 logging.info(message)
Jon Salz3c493bb2013-02-07 17:24:58 +08001727 self.last_log_disk_space_message = message
Jon Salzb92c5112012-09-21 15:40:11 +08001728 except: # pylint: disable=W0702
1729 logging.exception('Unable to get disk space used')
1730
Justin Chuang83813982013-05-13 01:26:32 +08001731 def check_battery(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001732 """Checks the current battery status.
Justin Chuang83813982013-05-13 01:26:32 +08001733
1734 Logs current battery charging level and status to log. If the battery level
1735 is lower below warning_low_battery_pct, send warning event to shopfloor.
1736 If the battery level is lower below critical_low_battery_pct, flush disks.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001737 """
Justin Chuang83813982013-05-13 01:26:32 +08001738 if not self.test_list.options.check_battery_period_secs:
1739 return
1740
1741 now = time.time()
1742 if (self.last_check_battery_time and
1743 now - self.last_check_battery_time <
1744 self.test_list.options.check_battery_period_secs):
1745 return
1746 self.last_check_battery_time = now
1747
1748 message = ''
1749 log_level = logging.INFO
1750 try:
Hung-Te Lin6a72c642015-12-13 22:09:09 +08001751 power = self.dut.power
Justin Chuang83813982013-05-13 01:26:32 +08001752 if not power.CheckBatteryPresent():
1753 message = 'Battery is not present'
1754 else:
1755 ac_present = power.CheckACPresent()
1756 charge_pct = power.GetChargePct(get_float=True)
1757 message = ('Current battery level %.1f%%, AC charger is %s' %
1758 (charge_pct, 'connected' if ac_present else 'disconnected'))
1759
1760 if charge_pct > self.test_list.options.critical_low_battery_pct:
1761 critical_low_battery = False
1762 else:
1763 critical_low_battery = True
1764 # Only sync disks when battery level is still above minimum
1765 # value. This can be used for offline analysis when shopfloor cannot
1766 # be connected.
1767 if charge_pct > MIN_BATTERY_LEVEL_FOR_DISK_SYNC:
1768 logging.warning('disk syncing for critical low battery situation')
1769 os.system('sync; sync; sync')
1770 else:
1771 logging.warning('disk syncing is cancelled '
1772 'because battery level is lower than %.1f',
1773 MIN_BATTERY_LEVEL_FOR_DISK_SYNC)
1774
1775 # Notify shopfloor server
1776 if (critical_low_battery or
1777 (not ac_present and
1778 charge_pct <= self.test_list.options.warning_low_battery_pct)):
1779 log_level = logging.WARNING
1780
1781 self.event_log.Log('low_battery',
1782 battery_level=charge_pct,
1783 charger_connected=ac_present,
1784 critical=critical_low_battery)
1785 self.log_watcher.KickWatchThread()
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001786 if self.test_list.options.enable_sync_log:
1787 self.system_log_manager.KickToSync()
Ricky Liang45c73e72015-01-15 15:00:30 +08001788 except: # pylint: disable=W0702
Justin Chuang83813982013-05-13 01:26:32 +08001789 logging.exception('Unable to check battery or notify shopfloor')
1790 finally:
1791 if message != self.last_check_battery_message:
1792 logging.log(log_level, message)
1793 self.last_check_battery_message = message
1794
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001795 def check_core_dump(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001796 """Checks if there is any core dumped file.
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001797
1798 Removes unwanted core dump files immediately.
1799 Syncs those files matching watch list to server with a delay between
1800 each sync. After the files have been synced to server, deletes the files.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001801 """
Vic Yang6cee2472014-10-22 17:18:52 -07001802 if not self.core_dump_manager:
1803 return
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001804 core_dump_files = self.core_dump_manager.ScanFiles()
1805 if core_dump_files:
1806 now = time.time()
1807 if (self.last_kick_sync_time and now - self.last_kick_sync_time <
1808 self.test_list.options.kick_sync_min_interval_secs):
1809 return
1810 self.last_kick_sync_time = now
1811
1812 # Sends event to server
1813 self.event_log.Log('core_dumped', files=core_dump_files)
1814 self.log_watcher.KickWatchThread()
1815
1816 # Syncs files to server
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001817 if self.test_list.options.enable_sync_log:
1818 self.system_log_manager.KickToSync(
Cheng-Yi Chiangd3516a32013-07-17 15:30:47 +08001819 core_dump_files, self.core_dump_manager.ClearFiles)
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001820
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001821 def check_log_rotation(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001822 """Checks log rotation file presence/absence according to test_list option.
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001823
1824 Touch /var/lib/cleanup_logs_paused if test_list.options.disable_log_rotation
1825 is True, delete it otherwise. This must be done in idle loop because
1826 autotest client will touch /var/lib/cleanup_logs_paused each time it runs
1827 an autotest.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001828 """
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001829 if sys_utils.InChroot():
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001830 return
1831 try:
1832 if self.test_list.options.disable_log_rotation:
1833 open(CLEANUP_LOGS_PAUSED, 'w').close()
1834 else:
1835 file_utils.TryUnlink(CLEANUP_LOGS_PAUSED)
1836 except: # pylint: disable=W0702
1837 # Oh well. Logs an error (but no trace)
1838 logging.info(
1839 'Unable to %s %s: %s',
1840 'touch' if self.test_list.options.disable_log_rotation else 'delete',
Hung-Te Linf707b242016-01-08 23:11:42 +08001841 CLEANUP_LOGS_PAUSED, debug_utils.FormatExceptionOnly())
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001842
Jon Salz8fa8e832012-07-13 19:04:09 +08001843 def sync_time_in_background(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001844 """Writes out current time and tries to sync with shopfloor server."""
Jon Salzb22d1172012-08-06 10:38:57 +08001845 if not self.time_sanitizer:
1846 return
1847
1848 # Write out the current time.
1849 self.time_sanitizer.SaveTime()
1850
Jon Salz54882d02012-08-31 01:57:54 +08001851 if not self._should_sync_time():
Jon Salz8fa8e832012-07-13 19:04:09 +08001852 return
1853
1854 now = time.time()
1855 if self.last_sync_time and (
1856 now - self.last_sync_time <
1857 self.test_list.options.sync_time_period_secs):
1858 # Not yet time for another check.
1859 return
1860 self.last_sync_time = now
1861
1862 def target():
1863 try:
Jon Salz54882d02012-08-31 01:57:54 +08001864 self.sync_time_with_shopfloor_server()
Jon Salz8fa8e832012-07-13 19:04:09 +08001865 except: # pylint: disable=W0702
1866 # Oh well. Log an error (but no trace)
1867 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +08001868 'Unable to get time from shopfloor server: %s',
Hung-Te Linf707b242016-01-08 23:11:42 +08001869 debug_utils.FormatExceptionOnly())
Jon Salz8fa8e832012-07-13 19:04:09 +08001870
1871 thread = threading.Thread(target=target)
1872 thread.daemon = True
1873 thread.start()
1874
Peter Ammon1e1ec572014-06-26 17:56:32 -07001875 def perform_periodic_tasks(self):
1876 """Override of base method to perform periodic work.
Vic Yang4953fc12012-07-26 16:19:53 +08001877
Peter Ammon1e1ec572014-06-26 17:56:32 -07001878 This method must not raise exceptions.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001879 """
Peter Ammon1e1ec572014-06-26 17:56:32 -07001880 super(Goofy, self).perform_periodic_tasks()
Jon Salzb22d1172012-08-06 10:38:57 +08001881
Vic Yang311ddb82012-09-26 12:08:28 +08001882 self.check_exclusive()
cychiang21886742012-07-05 15:16:32 +08001883 self.check_for_updates()
Jon Salz8fa8e832012-07-13 19:04:09 +08001884 self.sync_time_in_background()
Jon Salzb92c5112012-09-21 15:40:11 +08001885 self.log_disk_space_stats()
Justin Chuang83813982013-05-13 01:26:32 +08001886 self.check_battery()
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001887 self.check_core_dump()
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001888 self.check_log_rotation()
Jon Salz57717ca2012-04-04 16:47:25 +08001889
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001890 def handle_event_logs(self, chunks, periodic=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001891 """Callback for event watcher.
Jon Salz258a40c2012-04-19 12:34:01 +08001892
Jon Salz0697cbf2012-07-04 15:14:04 +08001893 Attempts to upload the event logs to the shopfloor server.
Vic Yang93027612013-05-06 02:42:49 +08001894
1895 Args:
Jon Salzd15bbcf2013-05-21 17:33:57 +08001896 chunks: A list of Chunk objects.
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001897 periodic: This event log handling is periodic. Error messages
1898 will only be shown for the first time.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001899 """
Vic Yang93027612013-05-06 02:42:49 +08001900 first_exception = None
1901 exception_count = 0
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001902 # Suppress error messages for periodic event syncing except for the
1903 # first time. If event syncing is not periodic, always show the error
1904 # messages.
1905 quiet = self._suppress_event_log_error_messages if periodic else False
Vic Yang93027612013-05-06 02:42:49 +08001906
Jon Salzd15bbcf2013-05-21 17:33:57 +08001907 for chunk in chunks:
Vic Yang93027612013-05-06 02:42:49 +08001908 try:
Jon Salzcddb6402013-05-23 12:56:42 +08001909 description = 'event logs (%s)' % str(chunk)
Vic Yang93027612013-05-06 02:42:49 +08001910 start_time = time.time()
1911 shopfloor_client = shopfloor.get_instance(
Ricky Liang45c73e72015-01-15 15:00:30 +08001912 detect=True,
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001913 timeout=self.test_list.options.shopfloor_timeout_secs,
1914 quiet=quiet)
Ricky Liang45c73e72015-01-15 15:00:30 +08001915 shopfloor_client.UploadEvent(chunk.log_name + '.' +
Jon Salzd15bbcf2013-05-21 17:33:57 +08001916 event_log.GetReimageId(),
1917 Binary(chunk.chunk))
Vic Yang93027612013-05-06 02:42:49 +08001918 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +08001919 'Successfully synced %s in %.03f s',
1920 description, time.time() - start_time)
1921 except: # pylint: disable=W0702
Hung-Te Linf707b242016-01-08 23:11:42 +08001922 first_exception = (first_exception or
1923 (chunk.log_name + ': ' +
1924 debug_utils.FormatExceptionOnly()))
Vic Yang93027612013-05-06 02:42:49 +08001925 exception_count += 1
1926
1927 if exception_count:
1928 if exception_count == 1:
1929 msg = 'Log upload failed: %s' % first_exception
1930 else:
1931 msg = '%d log upload failed; first is: %s' % (
1932 exception_count, first_exception)
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001933 # For periodic event log syncing, only show the first error messages.
1934 if periodic:
1935 if not self._suppress_event_log_error_messages:
1936 self._suppress_event_log_error_messages = True
1937 logging.warning('Suppress periodic shopfloor error messages for '
1938 'event log syncing after the first one.')
1939 raise Exception(msg)
1940 # For event log syncing by request, show the error messages.
1941 else:
1942 raise Exception(msg)
Vic Yang93027612013-05-06 02:42:49 +08001943
Ricky Liang45c73e72015-01-15 15:00:30 +08001944 def run_tests_with_status(self, statuses_to_run, starting_at=None, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001945 """Runs all top-level tests with a particular status.
Jon Salz0405ab52012-03-16 15:26:52 +08001946
Jon Salz0697cbf2012-07-04 15:14:04 +08001947 All active tests, plus any tests to re-run, are reset.
Jon Salz57717ca2012-04-04 16:47:25 +08001948
Jon Salz0697cbf2012-07-04 15:14:04 +08001949 Args:
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001950 statuses_to_run: The particular status that caller wants to run.
Jon Salz0697cbf2012-07-04 15:14:04 +08001951 starting_at: If provided, only auto-runs tests beginning with
1952 this test.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001953 root: The root of tests to run. If not provided, it will be
1954 the root of all tests.
1955 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001956 root = root or self.test_list
Jon Salz57717ca2012-04-04 16:47:25 +08001957
Jon Salz0697cbf2012-07-04 15:14:04 +08001958 if starting_at:
1959 # Make sure they passed a test, not a string.
1960 assert isinstance(starting_at, factory.FactoryTest)
Jon Salz0405ab52012-03-16 15:26:52 +08001961
Jon Salz0697cbf2012-07-04 15:14:04 +08001962 tests_to_reset = []
1963 tests_to_run = []
Jon Salz0405ab52012-03-16 15:26:52 +08001964
Jon Salz0697cbf2012-07-04 15:14:04 +08001965 found_starting_at = False
Jon Salz0405ab52012-03-16 15:26:52 +08001966
Jon Salz0697cbf2012-07-04 15:14:04 +08001967 for test in root.get_top_level_tests():
1968 if starting_at:
1969 if test == starting_at:
1970 # We've found starting_at; do auto-run on all
1971 # subsequent tests.
1972 found_starting_at = True
1973 if not found_starting_at:
1974 # Don't start this guy yet
1975 continue
Jon Salz0405ab52012-03-16 15:26:52 +08001976
Jon Salz0697cbf2012-07-04 15:14:04 +08001977 status = test.get_state().status
1978 if status == TestState.ACTIVE or status in statuses_to_run:
1979 # Reset the test (later; we will need to abort
1980 # all active tests first).
1981 tests_to_reset.append(test)
1982 if status in statuses_to_run:
1983 tests_to_run.append(test)
Jon Salz0405ab52012-03-16 15:26:52 +08001984
Jon Salz6dc031d2013-06-19 13:06:23 +08001985 self.abort_active_tests('Operator requested run/re-run of certain tests')
Jon Salz258a40c2012-04-19 12:34:01 +08001986
Jon Salz0697cbf2012-07-04 15:14:04 +08001987 # Reset all statuses of the tests to run (in case any tests were active;
1988 # we want them to be run again).
1989 for test_to_reset in tests_to_reset:
1990 for test in test_to_reset.walk():
1991 test.update_state(status=TestState.UNTESTED)
Jon Salz57717ca2012-04-04 16:47:25 +08001992
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +08001993 self.run_tests(tests_to_run, [TestState.UNTESTED])
Jon Salz0405ab52012-03-16 15:26:52 +08001994
Jon Salz0697cbf2012-07-04 15:14:04 +08001995 def restart_tests(self, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001996 """Restarts all tests."""
Jon Salz0697cbf2012-07-04 15:14:04 +08001997 root = root or self.test_list
Jon Salz0405ab52012-03-16 15:26:52 +08001998
Jon Salz6dc031d2013-06-19 13:06:23 +08001999 self.abort_active_tests('Operator requested restart of certain tests')
Jon Salz0697cbf2012-07-04 15:14:04 +08002000 for test in root.walk():
Ricky Liangfea4ac92014-08-21 11:55:59 +08002001 test.update_state(status=TestState.UNTESTED)
Jon Salz0697cbf2012-07-04 15:14:04 +08002002 self.run_tests(root)
Hung-Te Lin96632362012-03-20 21:14:18 +08002003
Jon Salz0697cbf2012-07-04 15:14:04 +08002004 def auto_run(self, starting_at=None, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002005 """"Auto-runs" tests that have not been run yet.
Hung-Te Lin96632362012-03-20 21:14:18 +08002006
Jon Salz0697cbf2012-07-04 15:14:04 +08002007 Args:
2008 starting_at: If provide, only auto-runs tests beginning with
2009 this test.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002010 root: If provided, the root of tests to run. If not provided, the root
2011 will be test_list (root of all tests).
2012 """
Jon Salz0697cbf2012-07-04 15:14:04 +08002013 root = root or self.test_list
2014 self.run_tests_with_status([TestState.UNTESTED, TestState.ACTIVE],
Ricky Liang45c73e72015-01-15 15:00:30 +08002015 starting_at=starting_at,
2016 root=root)
Jon Salz968e90b2012-03-18 16:12:43 +08002017
Jon Salz0697cbf2012-07-04 15:14:04 +08002018 def re_run_failed(self, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002019 """Re-runs failed tests."""
Jon Salz0697cbf2012-07-04 15:14:04 +08002020 root = root or self.test_list
2021 self.run_tests_with_status([TestState.FAILED], root=root)
Jon Salz57717ca2012-04-04 16:47:25 +08002022
Jon Salz0697cbf2012-07-04 15:14:04 +08002023 def show_review_information(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002024 """Event handler for showing review information screen.
Jon Salz57717ca2012-04-04 16:47:25 +08002025
Peter Ammon1e1ec572014-06-26 17:56:32 -07002026 The information screen is rendered by main UI program (ui.py), so in
Jon Salz0697cbf2012-07-04 15:14:04 +08002027 goofy we only need to kill all active tests, set them as untested, and
2028 clear remaining tests.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002029 """
Jon Salz0697cbf2012-07-04 15:14:04 +08002030 self.kill_active_tests(False)
Jon Salza6711d72012-07-18 14:33:03 +08002031 self.cancel_pending_tests()
Jon Salz57717ca2012-04-04 16:47:25 +08002032
Jon Salz0697cbf2012-07-04 15:14:04 +08002033 def handle_switch_test(self, event):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002034 """Switches to a particular test.
Jon Salz0405ab52012-03-16 15:26:52 +08002035
Ricky Liang6fe218c2013-12-27 15:17:17 +08002036 Args:
2037 event: The SWITCH_TEST event.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002038 """
Jon Salz0697cbf2012-07-04 15:14:04 +08002039 test = self.test_list.lookup_path(event.path)
2040 if not test:
2041 logging.error('Unknown test %r', event.key)
2042 return
Jon Salz73e0fd02012-04-04 11:46:38 +08002043
Jon Salz0697cbf2012-07-04 15:14:04 +08002044 invoc = self.invocations.get(test)
2045 if invoc and test.backgroundable:
2046 # Already running: just bring to the front if it
2047 # has a UI.
2048 logging.info('Setting visible test to %s', test.path)
Jon Salz36fbbb52012-07-05 13:45:06 +08002049 self.set_visible_test(test)
Jon Salz0697cbf2012-07-04 15:14:04 +08002050 return
Jon Salz73e0fd02012-04-04 11:46:38 +08002051
Jon Salz6dc031d2013-06-19 13:06:23 +08002052 self.abort_active_tests('Operator requested abort (switch_test)')
Jon Salz0697cbf2012-07-04 15:14:04 +08002053 for t in test.walk():
2054 t.update_state(status=TestState.UNTESTED)
Jon Salz73e0fd02012-04-04 11:46:38 +08002055
Jon Salz0697cbf2012-07-04 15:14:04 +08002056 if self.test_list.options.auto_run_on_keypress:
2057 self.auto_run(starting_at=test)
2058 else:
2059 self.run_tests(test)
Jon Salz73e0fd02012-04-04 11:46:38 +08002060
Wei-Ning Huang38b75f02015-02-25 18:25:14 +08002061 def handle_key_filter_mode(self, event):
2062 if self.key_filter:
2063 if getattr(event, 'enabled'):
2064 self.key_filter.Start()
2065 else:
2066 self.key_filter.Stop()
2067
Jon Salz0697cbf2012-07-04 15:14:04 +08002068 def wait(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002069 """Waits for all pending invocations.
Jon Salz0697cbf2012-07-04 15:14:04 +08002070
2071 Useful for testing.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002072 """
Jon Salz1acc8742012-07-17 17:45:55 +08002073 while self.invocations:
2074 for k, v in self.invocations.iteritems():
2075 logging.info('Waiting for %s to complete...', k)
2076 v.thread.join()
2077 self.reap_completed_tests()
Jon Salz0697cbf2012-07-04 15:14:04 +08002078
Claire Changd1961a22015-08-05 16:15:55 +08002079 def test_fail(self, test):
Hung-Te Lin410f70a2015-12-15 14:53:42 +08002080 self.dut.hooks.OnTestFailure(test)
Claire Changd1961a22015-08-05 16:15:55 +08002081 if self.link_manager:
2082 self.link_manager.UpdateStatus(False)
2083
Hung-Te Linf2f78f72012-02-08 19:27:11 +08002084if __name__ == '__main__':
Peter Ammona3d298c2014-09-23 10:11:02 -07002085 Goofy.run_main_and_exit()