blob: 559c9ecdd4d87aa7b1e5fe0879b6108857c450f4 [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 Salz51528e12012-07-02 18:54:45 +080045from cros.factory.test import shopfloor
Hung-Te Lin6a72c642015-12-13 22:09:09 +080046from cros.factory.test import state
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +080047from cros.factory.test.env import paths
Ricky Liang6fe218c2013-12-27 15:17:17 +080048from cros.factory.test.e2e_test.common import (
49 AutomationMode, AutomationModePrompt, ParseAutomationMode)
Jon Salz83591782012-06-26 11:09:58 +080050from cros.factory.test.event import Event
51from cros.factory.test.event import EventClient
52from cros.factory.test.event import EventServer
Hung-Te Lin91492a12014-11-25 18:56:30 +080053from cros.factory.test.event_log_watcher import EventLogWatcher
jcliangcd688182012-08-20 21:01:26 +080054from cros.factory.test.factory import TestState
Hung-Te Lin3f096842016-01-13 17:37:06 +080055from cros.factory.test.rules import phase
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +080056from cros.factory.test.test_lists import test_lists
Hung-Te Linc367ac02015-12-22 19:33:23 +080057from cros.factory.test.utils.charge_manager import ChargeManager
58from cros.factory.test.utils.core_dump_manager import CoreDumpManager
59from cros.factory.test.utils.cpufreq_manager import CpufreqManager
Dean Liao592e4d52013-01-10 20:06:39 +080060from cros.factory.tools.key_filter import KeyFilter
Hung-Te Lind3ee0102015-12-28 17:21:50 +080061from cros.factory.tools import disk_space
Hung-Te Linf707b242016-01-08 23:11:42 +080062from cros.factory.utils import debug_utils
Jon Salz2af235d2013-06-24 14:47:21 +080063from cros.factory.utils import file_utils
Joel Kitchingb85ed7f2014-10-08 18:24:39 +080064from cros.factory.utils import net_utils
Hung-Te Lin4e6357c2016-01-08 14:32:00 +080065from cros.factory.utils import process_utils
66from cros.factory.utils import sys_utils
67from cros.factory.utils import time_utils
Hung-Te Linf707b242016-01-08 23:11:42 +080068from cros.factory.utils import type_utils
Hung-Te Linf2f78f72012-02-08 19:27:11 +080069
70
Hung-Te Linf2f78f72012-02-08 19:27:11 +080071HWID_CFG_PATH = '/usr/local/share/chromeos-hwid/cfg'
Ricky Liang45c73e72015-01-15 15:00:30 +080072CACHES_DIR = os.path.join(factory.get_state_root(), 'caches')
Hung-Te Linf2f78f72012-02-08 19:27:11 +080073
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +080074CLEANUP_LOGS_PAUSED = '/var/lib/cleanup_logs_paused'
75
Jon Salz5c344f62012-07-13 14:31:16 +080076# Value for tests_after_shutdown that forces auto-run (e.g., after
77# a factory update, when the available set of tests might change).
78FORCE_AUTO_RUN = 'force_auto_run'
79
Justin Chuang83813982013-05-13 01:26:32 +080080# Sync disks when battery level is higher than this value.
81# Otherwise, power loss during disk sync operation may incur even worse outcome.
82MIN_BATTERY_LEVEL_FOR_DISK_SYNC = 1.0
83
Ricky Liang45c73e72015-01-15 15:00:30 +080084MAX_CRASH_FILE_SIZE = 64 * 1024
Jon Salze12c2b32013-06-25 16:24:34 +080085
Hung-Te Linf707b242016-01-08 23:11:42 +080086Status = type_utils.Enum(['UNINITIALIZED', 'INITIALIZING', 'RUNNING',
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +080087 'TERMINATING', 'TERMINATED'])
Jon Salzd7550792013-07-12 05:49:27 +080088
Ricky Liang45c73e72015-01-15 15:00:30 +080089
Hung-Te Linf2f78f72012-02-08 19:27:11 +080090def get_hwid_cfg():
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +080091 """Returns the HWID config tag, or an empty string if none can be found."""
Jon Salz0697cbf2012-07-04 15:14:04 +080092 if 'CROS_HWID' in os.environ:
93 return os.environ['CROS_HWID']
94 if os.path.exists(HWID_CFG_PATH):
Ricky Liang45c73e72015-01-15 15:00:30 +080095 with open(HWID_CFG_PATH, 'r') as hwid_cfg_handle:
Jon Salz0697cbf2012-07-04 15:14:04 +080096 return hwid_cfg_handle.read().strip()
97 return ''
Hung-Te Linf2f78f72012-02-08 19:27:11 +080098
99
Jon Salz73e0fd02012-04-04 11:46:38 +0800100_inited_logging = False
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800101
Ricky Liang45c73e72015-01-15 15:00:30 +0800102
Peter Ammon1e1ec572014-06-26 17:56:32 -0700103class Goofy(GoofyBase):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800104 """The main factory flow.
Jon Salz0697cbf2012-07-04 15:14:04 +0800105
106 Note that all methods in this class must be invoked from the main
107 (event) thread. Other threads, such as callbacks and TestInvocation
108 methods, should instead post events on the run queue.
109
110 TODO: Unit tests. (chrome-os-partner:7409)
111
112 Properties:
113 uuid: A unique UUID for this invocation of Goofy.
114 state_instance: An instance of FactoryState.
115 state_server: The FactoryState XML/RPC server.
116 state_server_thread: A thread running state_server.
117 event_server: The EventServer socket server.
118 event_server_thread: A thread running event_server.
119 event_client: A client to the event server.
120 connection_manager: The connection_manager object.
Cheng-Yi Chiang835f2682013-05-06 22:15:48 +0800121 system_log_manager: The SystemLogManager object.
122 core_dump_manager: The CoreDumpManager object.
Jon Salz0697cbf2012-07-04 15:14:04 +0800123 ui_process: The factory ui process object.
Jon Salz0697cbf2012-07-04 15:14:04 +0800124 invocations: A map from FactoryTest objects to the corresponding
125 TestInvocations objects representing active tests.
126 tests_to_run: A deque of tests that should be run when the current
127 test(s) complete.
128 options: Command-line options.
129 args: Command-line args.
130 test_list: The test list.
Jon Salz128b0932013-07-03 16:55:26 +0800131 test_lists: All new-style test lists.
Ricky Liang4bff3e32014-02-20 18:46:11 +0800132 run_id: The identifier for latest test run.
133 scheduled_run_tests: The list of tests scheduled for latest test run.
Jon Salz0697cbf2012-07-04 15:14:04 +0800134 event_handlers: Map of Event.Type to the method used to handle that
135 event. If the method has an 'event' argument, the event is passed
136 to the handler.
Jon Salz3c493bb2013-02-07 17:24:58 +0800137 last_log_disk_space_message: The last message we logged about disk space
138 (to avoid duplication).
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +0800139 last_kick_sync_time: The last time to kick system_log_manager to sync
140 because of core dump files (to avoid kicking too soon then abort the
141 sync.)
Jon Salz416f9cc2013-05-10 18:32:50 +0800142 hooks: A Hooks object containing hooks for various Goofy actions.
Jon Salzd7550792013-07-12 05:49:27 +0800143 status: The current Goofy status (a member of the Status enum).
Peter Ammon948b7172014-07-15 12:43:06 -0700144 link_manager: Instance of PresenterLinkManager for communicating
145 with GoofyPresenter
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800146 """
Ricky Liang45c73e72015-01-15 15:00:30 +0800147
Jon Salz0697cbf2012-07-04 15:14:04 +0800148 def __init__(self):
Peter Ammon1e1ec572014-06-26 17:56:32 -0700149 super(Goofy, self).__init__()
Jon Salz0697cbf2012-07-04 15:14:04 +0800150 self.uuid = str(uuid.uuid4())
151 self.state_instance = None
152 self.state_server = None
153 self.state_server_thread = None
Jon Salz16d10542012-07-23 12:18:45 +0800154 self.goofy_rpc = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800155 self.event_server = None
156 self.event_server_thread = None
157 self.event_client = None
158 self.connection_manager = None
Vic Yang4953fc12012-07-26 16:19:53 +0800159 self.charge_manager = None
Dean Liao88b93192014-10-23 19:37:41 +0800160 self._can_charge = True
Jon Salz8fa8e832012-07-13 19:04:09 +0800161 self.time_sanitizer = None
162 self.time_synced = False
Jon Salz0697cbf2012-07-04 15:14:04 +0800163 self.log_watcher = None
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800164 self.system_log_manager = None
Cheng-Yi Chiang835f2682013-05-06 22:15:48 +0800165 self.core_dump_manager = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800166 self.event_log = None
Vic Yange2c76a82014-10-30 12:48:19 -0700167 self.autotest_prespawner = None
168 self.pytest_prespawner = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800169 self.ui_process = None
Vic Yanga3cecf82014-12-26 00:44:21 -0800170 self._ui_initialized = False
Jon Salzc79a9982012-08-30 04:42:01 +0800171 self.dummy_shopfloor = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800172 self.invocations = {}
173 self.tests_to_run = deque()
174 self.visible_test = None
175 self.chrome = None
Jon Salz416f9cc2013-05-10 18:32:50 +0800176 self.hooks = None
Vic Yangd8990da2013-06-27 16:57:43 +0800177 self.cpu_usage_watcher = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800178
179 self.options = None
180 self.args = None
181 self.test_list = None
Jon Salz128b0932013-07-03 16:55:26 +0800182 self.test_lists = None
Ricky Liang4bff3e32014-02-20 18:46:11 +0800183 self.run_id = None
184 self.scheduled_run_tests = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800185 self.env = None
Jon Salzb22d1172012-08-06 10:38:57 +0800186 self.last_idle = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800187 self.last_shutdown_time = None
cychiang21886742012-07-05 15:16:32 +0800188 self.last_update_check = None
Cheng-Yi Chiang194d3c02015-03-16 14:37:15 +0800189 self._suppress_periodic_update_messages = False
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +0800190 self._suppress_event_log_error_messages = False
Jon Salz8fa8e832012-07-13 19:04:09 +0800191 self.last_sync_time = None
Jon Salzb92c5112012-09-21 15:40:11 +0800192 self.last_log_disk_space_time = None
Jon Salz3c493bb2013-02-07 17:24:58 +0800193 self.last_log_disk_space_message = None
Justin Chuang83813982013-05-13 01:26:32 +0800194 self.last_check_battery_time = None
195 self.last_check_battery_message = None
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +0800196 self.last_kick_sync_time = None
Vic Yang311ddb82012-09-26 12:08:28 +0800197 self.exclusive_items = set()
Jon Salz0f996602012-10-03 15:26:48 +0800198 self.event_log = None
Dean Liao592e4d52013-01-10 20:06:39 +0800199 self.key_filter = None
Jon Salzce6a7f82013-06-10 18:22:54 +0800200 self.cpufreq_manager = None
Jon Salzd7550792013-07-12 05:49:27 +0800201 self.status = Status.UNINITIALIZED
Ricky Liang36512a32014-07-25 11:47:04 +0800202 self.ready_for_ui_connection = False
Peter Ammon1e1ec572014-06-26 17:56:32 -0700203 self.link_manager = None
Hung-Te Linef7f2be2015-07-20 20:38:51 +0800204 self.is_restart_requested = False
Jon Salz0697cbf2012-07-04 15:14:04 +0800205
Hung-Te Lin6a72c642015-12-13 22:09:09 +0800206 # TODO(hungte) Support controlling remote DUT.
207 self.dut = dut.Create()
208
Jon Salz85a39882012-07-05 16:45:04 +0800209 def test_or_root(event, parent_or_group=True):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800210 """Returns the test affected by a particular event.
Jon Salz85a39882012-07-05 16:45:04 +0800211
212 Args:
213 event: The event containing an optional 'path' attribute.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800214 parent_or_group: If True, returns the top-level parent for a test (the
Jon Salz85a39882012-07-05 16:45:04 +0800215 root node of the tests that need to be run together if the given test
216 path is to be run).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800217 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800218 try:
219 path = event.path
220 except AttributeError:
221 path = None
222
223 if path:
Jon Salz85a39882012-07-05 16:45:04 +0800224 test = self.test_list.lookup_path(path)
225 if parent_or_group:
226 test = test.get_top_level_parent_or_group()
227 return test
Jon Salz0697cbf2012-07-04 15:14:04 +0800228 else:
229 return self.test_list
230
231 self.event_handlers = {
Ricky Liang45c73e72015-01-15 15:00:30 +0800232 Event.Type.SWITCH_TEST: self.handle_switch_test,
233 Event.Type.SHOW_NEXT_ACTIVE_TEST:
234 lambda event: self.show_next_active_test(),
235 Event.Type.RESTART_TESTS:
236 lambda event: self.restart_tests(root=test_or_root(event)),
237 Event.Type.AUTO_RUN:
238 lambda event: self.auto_run(root=test_or_root(event)),
239 Event.Type.RE_RUN_FAILED:
240 lambda event: self.re_run_failed(root=test_or_root(event)),
241 Event.Type.RUN_TESTS_WITH_STATUS:
242 lambda event: self.run_tests_with_status(
243 event.status,
244 root=test_or_root(event)),
245 Event.Type.REVIEW:
246 lambda event: self.show_review_information(),
247 Event.Type.UPDATE_SYSTEM_INFO:
248 lambda event: self.update_system_info(),
249 Event.Type.STOP:
250 lambda event: self.stop(root=test_or_root(event, False),
251 fail=getattr(event, 'fail', False),
252 reason=getattr(event, 'reason', None)),
253 Event.Type.SET_VISIBLE_TEST:
254 lambda event: self.set_visible_test(
255 self.test_list.lookup_path(event.path)),
256 Event.Type.CLEAR_STATE:
257 lambda event: self.clear_state(
258 self.test_list.lookup_path(event.path)),
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800259 Event.Type.KEY_FILTER_MODE: self.handle_key_filter_mode,
Jon Salz0697cbf2012-07-04 15:14:04 +0800260 }
261
Jon Salz0697cbf2012-07-04 15:14:04 +0800262 self.web_socket_manager = None
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800263 self.terminal_manager = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800264
265 def destroy(self):
Ricky Liang74237a02014-09-18 15:11:23 +0800266 """Performs any shutdown tasks. Overrides base class method."""
Jon Salzd7550792013-07-12 05:49:27 +0800267 self.status = Status.TERMINATING
Jon Salz0697cbf2012-07-04 15:14:04 +0800268 if self.chrome:
269 self.chrome.kill()
270 self.chrome = None
Jon Salzc79a9982012-08-30 04:42:01 +0800271 if self.dummy_shopfloor:
272 self.dummy_shopfloor.kill()
273 self.dummy_shopfloor = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800274 if self.ui_process:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800275 process_utils.KillProcessTree(self.ui_process, 'ui')
Jon Salz0697cbf2012-07-04 15:14:04 +0800276 self.ui_process = None
277 if self.web_socket_manager:
278 logging.info('Stopping web sockets')
279 self.web_socket_manager.close()
280 self.web_socket_manager = None
281 if self.state_server_thread:
282 logging.info('Stopping state server')
283 self.state_server.shutdown()
284 self.state_server_thread.join()
285 self.state_server.server_close()
286 self.state_server_thread = None
287 if self.state_instance:
288 self.state_instance.close()
289 if self.event_server_thread:
290 logging.info('Stopping event server')
291 self.event_server.shutdown() # pylint: disable=E1101
292 self.event_server_thread.join()
293 self.event_server.server_close()
294 self.event_server_thread = None
295 if self.log_watcher:
296 if self.log_watcher.IsThreadStarted():
297 self.log_watcher.StopWatchThread()
298 self.log_watcher = None
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800299 if self.system_log_manager:
300 if self.system_log_manager.IsThreadRunning():
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +0800301 self.system_log_manager.Stop()
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800302 self.system_log_manager = None
Vic Yange2c76a82014-10-30 12:48:19 -0700303 if self.autotest_prespawner:
304 logging.info('Stopping autotest prespawner')
305 self.autotest_prespawner.stop()
306 self.autotest_prespawner = None
307 if self.pytest_prespawner:
308 logging.info('Stopping pytest prespawner')
309 self.pytest_prespawner.stop()
310 self.pytest_prespawner = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800311 if self.event_client:
312 logging.info('Closing event client')
313 self.event_client.close()
314 self.event_client = None
Jon Salzddf0d052013-06-18 12:52:44 +0800315 if self.cpufreq_manager:
316 self.cpufreq_manager.Stop()
Jon Salz0697cbf2012-07-04 15:14:04 +0800317 if self.event_log:
318 self.event_log.Close()
319 self.event_log = None
Dean Liao592e4d52013-01-10 20:06:39 +0800320 if self.key_filter:
321 self.key_filter.Stop()
Vic Yangd8990da2013-06-27 16:57:43 +0800322 if self.cpu_usage_watcher:
323 self.cpu_usage_watcher.terminate()
Peter Ammon1e1ec572014-06-26 17:56:32 -0700324 if self.link_manager:
325 self.link_manager.Stop()
326 self.link_manager = None
Dean Liao592e4d52013-01-10 20:06:39 +0800327
Peter Ammon1e1ec572014-06-26 17:56:32 -0700328 super(Goofy, self).destroy()
Jon Salz0697cbf2012-07-04 15:14:04 +0800329 logging.info('Done destroying Goofy')
Jon Salzd7550792013-07-12 05:49:27 +0800330 self.status = Status.TERMINATED
Jon Salz0697cbf2012-07-04 15:14:04 +0800331
332 def start_state_server(self):
Jon Salz2af235d2013-06-24 14:47:21 +0800333 # Before starting state server, remount stateful partitions with
334 # no commit flag. The default commit time (commit=600) makes corruption
335 # too likely.
Hung-Te Lin1968d9c2016-01-08 22:55:46 +0800336 sys_utils.ResetCommitTime()
Jon Salz2af235d2013-06-24 14:47:21 +0800337
Jon Salz0697cbf2012-07-04 15:14:04 +0800338 self.state_instance, self.state_server = (
Ricky Liang45c73e72015-01-15 15:00:30 +0800339 state.create_server(bind_address='0.0.0.0'))
Jon Salz16d10542012-07-23 12:18:45 +0800340 self.goofy_rpc = GoofyRPC(self)
341 self.goofy_rpc.RegisterMethods(self.state_instance)
Jon Salz0697cbf2012-07-04 15:14:04 +0800342 logging.info('Starting state server')
343 self.state_server_thread = threading.Thread(
Ricky Liang45c73e72015-01-15 15:00:30 +0800344 target=self.state_server.serve_forever,
345 name='StateServer')
Jon Salz0697cbf2012-07-04 15:14:04 +0800346 self.state_server_thread.start()
347
348 def start_event_server(self):
349 self.event_server = EventServer()
350 logging.info('Starting factory event server')
351 self.event_server_thread = threading.Thread(
Ricky Liang45c73e72015-01-15 15:00:30 +0800352 target=self.event_server.serve_forever,
353 name='EventServer') # pylint: disable=E1101
Jon Salz0697cbf2012-07-04 15:14:04 +0800354 self.event_server_thread.start()
355
356 self.event_client = EventClient(
Ricky Liang45c73e72015-01-15 15:00:30 +0800357 callback=self.handle_event, event_loop=self.run_queue)
Jon Salz0697cbf2012-07-04 15:14:04 +0800358
359 self.web_socket_manager = WebSocketManager(self.uuid)
Ricky Liang45c73e72015-01-15 15:00:30 +0800360 self.state_server.add_handler('/event',
361 self.web_socket_manager.handle_web_socket)
Jon Salz0697cbf2012-07-04 15:14:04 +0800362
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800363 def start_terminal_server(self):
364 self.terminal_manager = TerminalManager()
365 self.state_server.add_handler('/pty',
366 self.terminal_manager.handle_web_socket)
367
Jon Salz0697cbf2012-07-04 15:14:04 +0800368 def start_ui(self):
369 ui_proc_args = [
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +0800370 os.path.join(paths.FACTORY_PACKAGE_PATH, 'test', 'ui.py'),
Ricky Liang45c73e72015-01-15 15:00:30 +0800371 self.options.test_list
372 ]
Jon Salz0697cbf2012-07-04 15:14:04 +0800373 if self.options.verbose:
374 ui_proc_args.append('-v')
375 logging.info('Starting ui %s', ui_proc_args)
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800376 self.ui_process = process_utils.Spawn(ui_proc_args)
Jon Salz0697cbf2012-07-04 15:14:04 +0800377 logging.info('Waiting for UI to come up...')
378 self.event_client.wait(
Ricky Liang45c73e72015-01-15 15:00:30 +0800379 lambda event: event.type == Event.Type.UI_READY)
Jon Salz0697cbf2012-07-04 15:14:04 +0800380 logging.info('UI has started')
381
382 def set_visible_test(self, test):
383 if self.visible_test == test:
384 return
Jon Salz2f2d42c2012-07-30 12:30:34 +0800385 if test and not test.has_ui:
386 return
Jon Salz0697cbf2012-07-04 15:14:04 +0800387
388 if test:
389 test.update_state(visible=True)
390 if self.visible_test:
391 self.visible_test.update_state(visible=False)
392 self.visible_test = test
393
Ricky Liang48e47f92014-02-26 19:31:51 +0800394 def log_startup_messages(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800395 """Logs the tail of var/log/messages and mosys and EC console logs."""
Jon Salzd4306c82012-11-30 15:16:36 +0800396 # TODO(jsalz): This is mostly a copy-and-paste of code in init_states,
397 # for factory-3004.B only. Consolidate and merge back to ToT.
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800398 if sys_utils.InChroot():
Jon Salzd4306c82012-11-30 15:16:36 +0800399 return
400
401 try:
Hung-Te Lin1a4e30c2016-01-08 23:25:10 +0800402 var_log_messages = sys_utils.GetVarLogMessagesBeforeReboot()
Jon Salzd4306c82012-11-30 15:16:36 +0800403 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +0800404 'Tail of /var/log/messages before last reboot:\n'
405 '%s', ('\n'.join(
406 ' ' + x for x in var_log_messages)))
Jon Salzd4306c82012-11-30 15:16:36 +0800407 except: # pylint: disable=W0702
408 logging.exception('Unable to grok /var/log/messages')
409
410 try:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800411 mosys_log = process_utils.Spawn(
Jon Salzd4306c82012-11-30 15:16:36 +0800412 ['mosys', 'eventlog', 'list'],
413 read_stdout=True, log_stderr_on_error=True).stdout_data
414 logging.info('System eventlog from mosys:\n%s\n', mosys_log)
415 except: # pylint: disable=W0702
416 logging.exception('Unable to read mosys eventlog')
417
Dean Liao88b93192014-10-23 19:37:41 +0800418 self.log_ec_console()
419 self.log_ec_panic_info()
420
421 @staticmethod
422 def log_ec_console():
423 """Logs EC console log into logging.info.
424
425 It logs an error message in logging.exception if an exception is raised
426 when getting EC console log.
427 For unsupported device, it logs unsupport message in logging.info
428
429 Returns:
430 EC console log string.
431 """
Jon Salzd4306c82012-11-30 15:16:36 +0800432 try:
Hung-Te Linb3a09642015-12-14 18:57:23 +0800433 ec_console_log = dut.Create().ec.GetECConsoleLog()
Jon Salzd4306c82012-11-30 15:16:36 +0800434 logging.info('EC console log after reboot:\n%s\n', ec_console_log)
Dean Liao88b93192014-10-23 19:37:41 +0800435 return ec_console_log
436 except NotImplementedError:
437 logging.info('EC console log not supported')
Jon Salzd4306c82012-11-30 15:16:36 +0800438 except: # pylint: disable=W0702
439 logging.exception('Error retrieving EC console log')
440
Dean Liao88b93192014-10-23 19:37:41 +0800441 @staticmethod
442 def log_ec_panic_info():
443 """Logs EC panic info into logging.info.
444
445 It logs an error message in logging.exception if an exception is raised
446 when getting EC panic info.
447 For unsupported device, it logs unsupport message in logging.info
448
449 Returns:
450 EC panic info string.
451 """
Vic Yang079f9872013-07-01 11:32:00 +0800452 try:
Hung-Te Linb3a09642015-12-14 18:57:23 +0800453 ec_panic_info = dut.Create().ec.GetECPanicInfo()
Vic Yang079f9872013-07-01 11:32:00 +0800454 logging.info('EC panic info after reboot:\n%s\n', ec_panic_info)
Dean Liao88b93192014-10-23 19:37:41 +0800455 return ec_panic_info
456 except NotImplementedError:
457 logging.info('EC panic info is not supported')
Vic Yang079f9872013-07-01 11:32:00 +0800458 except: # pylint: disable=W0702
459 logging.exception('Error retrieving EC panic info')
460
Ricky Liang48e47f92014-02-26 19:31:51 +0800461 def shutdown(self, operation):
462 """Starts shutdown procedure.
463
464 Args:
Vic (Chun-Ju) Yang05b0d952014-04-28 17:39:09 +0800465 operation: The shutdown operation (reboot, full_reboot, or halt).
Ricky Liang48e47f92014-02-26 19:31:51 +0800466 """
467 active_tests = []
468 for test in self.test_list.walk():
469 if not test.is_leaf():
470 continue
471
472 test_state = test.get_state()
473 if test_state.status == TestState.ACTIVE:
474 active_tests.append(test)
475
Ricky Liang48e47f92014-02-26 19:31:51 +0800476 if not (len(active_tests) == 1 and
477 isinstance(active_tests[0], factory.ShutdownStep)):
478 logging.error(
479 'Calling Goofy shutdown outside of the shutdown factory test')
480 return
481
482 logging.info('Start Goofy shutdown (%s)', operation)
483 # Save pending test list in the state server
484 self.state_instance.set_shared_data(
485 'tests_after_shutdown',
486 [t.path for t in self.tests_to_run])
487 # Save shutdown time
488 self.state_instance.set_shared_data('shutdown_time', time.time())
489
490 with self.env.lock:
491 self.event_log.Log('shutdown', operation=operation)
492 shutdown_result = self.env.shutdown(operation)
493 if shutdown_result:
494 # That's all, folks!
Peter Ammon1e1ec572014-06-26 17:56:32 -0700495 self.run_enqueue(None)
Ricky Liang48e47f92014-02-26 19:31:51 +0800496 else:
497 # Just pass (e.g., in the chroot).
498 self.state_instance.set_shared_data('tests_after_shutdown', None)
499 # Send event with no fields to indicate that there is no
500 # longer a pending shutdown.
501 self.event_client.post_event(Event(Event.Type.PENDING_SHUTDOWN))
502
503 def handle_shutdown_complete(self, test):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800504 """Handles the case where a shutdown was detected during a shutdown step.
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800505
Ricky Liang6fe218c2013-12-27 15:17:17 +0800506 Args:
507 test: The ShutdownStep.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800508 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800509 test_state = test.update_state(increment_shutdown_count=1)
510 logging.info('Detected shutdown (%d of %d)',
Ricky Liang48e47f92014-02-26 19:31:51 +0800511 test_state.shutdown_count, test.iterations)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800512
Ricky Liang48e47f92014-02-26 19:31:51 +0800513 # Insert current shutdown test at the front of the list of tests to run
514 # after shutdown. This is to continue on post-shutdown verification in the
515 # shutdown step.
516 tests_after_shutdown = self.state_instance.get_shared_data(
517 'tests_after_shutdown', optional=True)
518 if not tests_after_shutdown:
519 self.state_instance.set_shared_data('tests_after_shutdown', [test.path])
520 elif isinstance(tests_after_shutdown, list):
521 self.state_instance.set_shared_data(
522 'tests_after_shutdown', [test.path] + tests_after_shutdown)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800523
Ricky Liang48e47f92014-02-26 19:31:51 +0800524 # Set 'post_shutdown' to inform shutdown test that a shutdown just occurred.
Ricky Liangb7eb8772014-09-15 18:05:22 +0800525 self.state_instance.set_shared_data(
526 state.POST_SHUTDOWN_TAG % test.path,
527 self.state_instance.get_test_state(test.path).invocation)
Jon Salz258a40c2012-04-19 12:34:01 +0800528
Jon Salz0697cbf2012-07-04 15:14:04 +0800529 def init_states(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800530 """Initializes all states on startup."""
Jon Salz0697cbf2012-07-04 15:14:04 +0800531 for test in self.test_list.get_all_tests():
532 # Make sure the state server knows about all the tests,
533 # defaulting to an untested state.
534 test.update_state(update_parent=False, visible=False)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800535
Jon Salz0697cbf2012-07-04 15:14:04 +0800536 var_log_messages = None
Vic Yanga9c32212012-08-16 20:07:54 +0800537 mosys_log = None
Vic Yange4c275d2012-08-28 01:50:20 +0800538 ec_console_log = None
Vic Yang079f9872013-07-01 11:32:00 +0800539 ec_panic_info = None
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800540
Jon Salz0697cbf2012-07-04 15:14:04 +0800541 # Any 'active' tests should be marked as failed now.
542 for test in self.test_list.walk():
Jon Salza6711d72012-07-18 14:33:03 +0800543 if not test.is_leaf():
544 # Don't bother with parents; they will be updated when their
545 # children are updated.
546 continue
547
Jon Salz0697cbf2012-07-04 15:14:04 +0800548 test_state = test.get_state()
549 if test_state.status != TestState.ACTIVE:
550 continue
551 if isinstance(test, factory.ShutdownStep):
552 # Shutdown while the test was active - that's good.
Ricky Liang48e47f92014-02-26 19:31:51 +0800553 self.handle_shutdown_complete(test)
Jon Salz0697cbf2012-07-04 15:14:04 +0800554 else:
555 # Unexpected shutdown. Grab /var/log/messages for context.
556 if var_log_messages is None:
557 try:
558 var_log_messages = (
Hung-Te Lin1a4e30c2016-01-08 23:25:10 +0800559 sys_utils.GetVarLogMessagesBeforeReboot())
Jon Salz0697cbf2012-07-04 15:14:04 +0800560 # Write it to the log, to make it easier to
561 # correlate with /var/log/messages.
562 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +0800563 'Unexpected shutdown. '
564 'Tail of /var/log/messages before last reboot:\n'
565 '%s', ('\n'.join(
566 ' ' + x for x in var_log_messages)))
Jon Salz0697cbf2012-07-04 15:14:04 +0800567 except: # pylint: disable=W0702
568 logging.exception('Unable to grok /var/log/messages')
569 var_log_messages = []
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800570
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800571 if mosys_log is None and not sys_utils.InChroot():
Jon Salz008f4ea2012-08-28 05:39:45 +0800572 try:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800573 mosys_log = process_utils.Spawn(
Jon Salz008f4ea2012-08-28 05:39:45 +0800574 ['mosys', 'eventlog', 'list'],
575 read_stdout=True, log_stderr_on_error=True).stdout_data
576 # Write it to the log also.
577 logging.info('System eventlog from mosys:\n%s\n', mosys_log)
578 except: # pylint: disable=W0702
579 logging.exception('Unable to read mosys eventlog')
Vic Yanga9c32212012-08-16 20:07:54 +0800580
Vic Yange4c275d2012-08-28 01:50:20 +0800581 if ec_console_log is None:
Dean Liao88b93192014-10-23 19:37:41 +0800582 ec_console_log = self.log_ec_console()
Vic Yange4c275d2012-08-28 01:50:20 +0800583
Vic Yang079f9872013-07-01 11:32:00 +0800584 if ec_panic_info is None:
Dean Liao88b93192014-10-23 19:37:41 +0800585 ec_panic_info = self.log_ec_panic_info()
Vic Yang079f9872013-07-01 11:32:00 +0800586
Jon Salz0697cbf2012-07-04 15:14:04 +0800587 error_msg = 'Unexpected shutdown while test was running'
588 self.event_log.Log('end_test',
Ricky Liang45c73e72015-01-15 15:00:30 +0800589 path=test.path,
590 status=TestState.FAILED,
591 invocation=test.get_state().invocation,
592 error_msg=error_msg,
593 var_log_messages='\n'.join(var_log_messages),
594 mosys_log=mosys_log)
Jon Salz0697cbf2012-07-04 15:14:04 +0800595 test.update_state(
Ricky Liang45c73e72015-01-15 15:00:30 +0800596 status=TestState.FAILED,
597 error_msg=error_msg)
Chun-Ta Lin87c2dac2015-05-02 01:35:01 -0700598 # Trigger the OnTestFailure callback.
Claire Changd1961a22015-08-05 16:15:55 +0800599 self.run_queue.put(lambda: self.test_fail(test))
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800600
Jon Salz50efe942012-07-26 11:54:10 +0800601 if not test.never_fails:
602 # For "never_fails" tests (such as "Start"), don't cancel
603 # pending tests, since reboot is expected.
604 factory.console.info('Unexpected shutdown while test %s '
605 'running; cancelling any pending tests',
606 test.path)
607 self.state_instance.set_shared_data('tests_after_shutdown', [])
Jon Salz69806bb2012-07-20 18:05:02 +0800608
Jon Salz008f4ea2012-08-28 05:39:45 +0800609 self.update_skipped_tests()
610
611 def update_skipped_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800612 """Updates skipped states based on run_if."""
Jon Salz885dcac2013-07-23 16:39:50 +0800613 env = TestArgEnv()
Ricky Liang45c73e72015-01-15 15:00:30 +0800614
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800615 def _evaluate_skip_from_run_if(test):
616 """Returns the run_if evaluation of the test.
617
618 Args:
619 test: A FactoryTest object.
620
621 Returns:
622 The run_if evaluation result. Returns False if the test has no
623 run_if argument.
624 """
625 value = None
626 if test.run_if_expr:
627 try:
628 value = test.run_if_expr(env)
629 except: # pylint: disable=W0702
630 logging.exception('Unable to evaluate run_if expression for %s',
631 test.path)
632 # But keep going; we have no choice. This will end up
633 # always activating the test.
634 elif test.run_if_table_name:
635 try:
636 aux = shopfloor.get_selected_aux_data(test.run_if_table_name)
637 value = aux.get(test.run_if_col)
638 except ValueError:
639 # Not available; assume it shouldn't be skipped
640 pass
641
642 if value is None:
643 skip = False
644 else:
645 skip = (not value) ^ t.run_if_not
646 return skip
647
648 # Gets all run_if evaluation, and stores results in skip_map.
649 skip_map = dict()
Jon Salz008f4ea2012-08-28 05:39:45 +0800650 for t in self.test_list.walk():
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800651 skip_map[t.path] = _evaluate_skip_from_run_if(t)
Jon Salz885dcac2013-07-23 16:39:50 +0800652
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800653 # Propagates the skip value from root of tree and updates skip_map.
654 def _update_skip_map_from_node(test, skip_from_parent):
655 """Updates skip_map from a given node.
Jon Salz885dcac2013-07-23 16:39:50 +0800656
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800657 Given a FactoryTest node and the skip value from parent, updates the
658 skip value of current node in the skip_map if skip value from parent is
659 True. If this node has children, recursively propagate this value to all
660 its children, that is, all its subtests.
661 Note that this function only updates value in skip_map, not the actual
662 test_list tree.
Jon Salz008f4ea2012-08-28 05:39:45 +0800663
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800664 Args:
665 test: The given FactoryTest object. It is a node in the test_list tree.
666 skip_from_parent: The skip value which propagates from the parent of
667 input node.
668 """
669 skip_this_tree = skip_from_parent or skip_map[test.path]
670 if skip_this_tree:
671 logging.info('Skip from node %r', test.path)
672 skip_map[test.path] = True
673 if test.is_leaf():
674 return
675 # Propagates skip value to its subtests
676 for subtest in test.subtests:
677 _update_skip_map_from_node(subtest, skip_this_tree)
678
679 _update_skip_map_from_node(self.test_list, False)
680
681 # Updates the skip value from skip_map to test_list tree. Also, updates test
682 # status if needed.
683 for t in self.test_list.walk():
684 skip = skip_map[t.path]
685 test_state = t.get_state()
686 if ((not skip) and
687 (test_state.status == TestState.PASSED) and
688 (test_state.error_msg == TestState.SKIPPED_MSG)):
689 # It was marked as skipped before, but now we need to run it.
690 # Mark as untested.
691 t.update_state(skip=skip, status=TestState.UNTESTED, error_msg='')
692 else:
693 t.update_state(skip=skip)
Jon Salz008f4ea2012-08-28 05:39:45 +0800694
Jon Salz0697cbf2012-07-04 15:14:04 +0800695 def show_next_active_test(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800696 """Rotates to the next visible active test."""
Jon Salz0697cbf2012-07-04 15:14:04 +0800697 self.reap_completed_tests()
698 active_tests = [
Ricky Liang45c73e72015-01-15 15:00:30 +0800699 t for t in self.test_list.walk()
700 if t.is_leaf() and t.get_state().status == TestState.ACTIVE]
Jon Salz0697cbf2012-07-04 15:14:04 +0800701 if not active_tests:
702 return
Jon Salz4f6c7172012-06-11 20:45:36 +0800703
Jon Salz0697cbf2012-07-04 15:14:04 +0800704 try:
705 next_test = active_tests[
Ricky Liang45c73e72015-01-15 15:00:30 +0800706 (active_tests.index(self.visible_test) + 1) % len(active_tests)]
Jon Salz0697cbf2012-07-04 15:14:04 +0800707 except ValueError: # visible_test not present in active_tests
708 next_test = active_tests[0]
Jon Salz4f6c7172012-06-11 20:45:36 +0800709
Jon Salz0697cbf2012-07-04 15:14:04 +0800710 self.set_visible_test(next_test)
Jon Salz4f6c7172012-06-11 20:45:36 +0800711
Jon Salz0697cbf2012-07-04 15:14:04 +0800712 def handle_event(self, event):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800713 """Handles an event from the event server."""
Jon Salz0697cbf2012-07-04 15:14:04 +0800714 handler = self.event_handlers.get(event.type)
715 if handler:
716 handler(event)
717 else:
718 # We don't register handlers for all event types - just ignore
719 # this event.
720 logging.debug('Unbound event type %s', event.type)
Jon Salz4f6c7172012-06-11 20:45:36 +0800721
Vic Yangaabf9fd2013-04-09 18:56:13 +0800722 def check_critical_factory_note(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800723 """Returns True if the last factory note is critical."""
Vic Yangaabf9fd2013-04-09 18:56:13 +0800724 notes = self.state_instance.get_shared_data('factory_note', True)
725 return notes and notes[-1]['level'] == 'CRITICAL'
726
Hung-Te Linef7f2be2015-07-20 20:38:51 +0800727 def schedule_restart(self):
728 """Schedules a restart event when any invocation is completed."""
729 self.is_restart_requested = True
730
731 def invocation_completion(self):
732 """Callback when an invocation is completed."""
733 if self.is_restart_requested:
734 logging.info('Restart by scheduled event.')
735 self.is_restart_requested = False
736 self.restart_tests()
737 else:
738 self.run_next_test()
739
Jon Salz0697cbf2012-07-04 15:14:04 +0800740 def run_next_test(self):
henryhsu4cc6b022014-04-22 17:12:42 +0800741 """Runs the next eligible test (or tests) in self.tests_to_run.
742
743 We have three kinds of the next eligible test:
744 1. normal
745 2. backgroundable
746 3. force_background
747
748 And we have four situations of the ongoing invocations:
749 a. only a running normal test
750 b. all running tests are backgroundable
751 c. all running tests are force_background
752 d. all running tests are any combination of backgroundable and
753 force_background
754
755 When a test would like to be run, it must follow the rules:
756 [1] cannot run with [abd]
757 [2] cannot run with [a]
758 All the other combinations are allowed
759 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800760 self.reap_completed_tests()
Vic Yangaabf9fd2013-04-09 18:56:13 +0800761 if self.tests_to_run and self.check_critical_factory_note():
762 self.tests_to_run.clear()
763 return
Jon Salz0697cbf2012-07-04 15:14:04 +0800764 while self.tests_to_run:
Ricky Liang6fe218c2013-12-27 15:17:17 +0800765 logging.debug('Tests to run: %s', [x.path for x in self.tests_to_run])
Jon Salz94eb56f2012-06-12 18:01:12 +0800766
Jon Salz0697cbf2012-07-04 15:14:04 +0800767 test = self.tests_to_run[0]
Jon Salz94eb56f2012-06-12 18:01:12 +0800768
Jon Salz0697cbf2012-07-04 15:14:04 +0800769 if test in self.invocations:
770 logging.info('Next test %s is already running', test.path)
771 self.tests_to_run.popleft()
772 return
Jon Salz94eb56f2012-06-12 18:01:12 +0800773
Jon Salza1412922012-07-23 16:04:17 +0800774 for requirement in test.require_run:
775 for i in requirement.test.walk():
776 if i.get_state().status == TestState.ACTIVE:
Jon Salz304a75d2012-07-06 11:14:15 +0800777 logging.info('Waiting for active test %s to complete '
Jon Salza1412922012-07-23 16:04:17 +0800778 'before running %s', i.path, test.path)
Jon Salz304a75d2012-07-06 11:14:15 +0800779 return
780
henryhsu4cc6b022014-04-22 17:12:42 +0800781 def is_normal_test(test):
782 return not (test.backgroundable or test.force_background)
783
784 # [1] cannot run with [abd].
785 if self.invocations and is_normal_test(test) and any(
786 [not x.force_background for x in self.invocations]):
787 logging.info('Waiting for non-force_background tests to '
788 'complete before running %s', test.path)
789 return
790
791 # [2] cannot run with [a].
792 if self.invocations and test.backgroundable and any(
793 [is_normal_test(x) for x in self.invocations]):
794 logging.info('Waiting for normal tests to '
795 'complete before running %s', test.path)
Jon Salz0697cbf2012-07-04 15:14:04 +0800796 return
Jon Salz94eb56f2012-06-12 18:01:12 +0800797
Jon Salz3e6f5202012-10-15 15:08:29 +0800798 if test.get_state().skip:
799 factory.console.info('Skipping test %s', test.path)
800 test.update_state(status=TestState.PASSED,
801 error_msg=TestState.SKIPPED_MSG)
802 self.tests_to_run.popleft()
803 continue
804
Jon Salz0697cbf2012-07-04 15:14:04 +0800805 self.tests_to_run.popleft()
Jon Salz94eb56f2012-06-12 18:01:12 +0800806
Jon Salz304a75d2012-07-06 11:14:15 +0800807 untested = set()
Jon Salza1412922012-07-23 16:04:17 +0800808 for requirement in test.require_run:
809 for i in requirement.test.walk():
810 if i == test:
Jon Salz304a75d2012-07-06 11:14:15 +0800811 # We've hit this test itself; stop checking
812 break
Jon Salza1412922012-07-23 16:04:17 +0800813 if ((i.get_state().status == TestState.UNTESTED) or
814 (requirement.passed and i.get_state().status !=
815 TestState.PASSED)):
Jon Salz304a75d2012-07-06 11:14:15 +0800816 # Found an untested test; move on to the next
817 # element in require_run.
Jon Salza1412922012-07-23 16:04:17 +0800818 untested.add(i)
Jon Salz304a75d2012-07-06 11:14:15 +0800819 break
820
821 if untested:
822 untested_paths = ', '.join(sorted([x.path for x in untested]))
823 if self.state_instance.get_shared_data('engineering_mode',
824 optional=True):
825 # In engineering mode, we'll let it go.
826 factory.console.warn('In engineering mode; running '
827 '%s even though required tests '
828 '[%s] have not completed',
829 test.path, untested_paths)
830 else:
831 # Not in engineering mode; mark it failed.
832 error_msg = ('Required tests [%s] have not been run yet'
833 % untested_paths)
834 factory.console.error('Not running %s: %s',
835 test.path, error_msg)
836 test.update_state(status=TestState.FAILED,
837 error_msg=error_msg)
838 continue
839
Ricky Liang48e47f92014-02-26 19:31:51 +0800840 if (isinstance(test, factory.ShutdownStep) and
Ricky Liangb7eb8772014-09-15 18:05:22 +0800841 self.state_instance.get_shared_data(
842 state.POST_SHUTDOWN_TAG % test.path, optional=True)):
Ricky Liang48e47f92014-02-26 19:31:51 +0800843 # Invoking post shutdown method of shutdown test. We should retain the
844 # iterations_left and retries_left of the original test state.
845 test_state = self.state_instance.get_test_state(test.path)
846 self._run_test(test, test_state.iterations_left,
847 test_state.retries_left)
848 else:
849 # Starts a new test run; reset iterations and retries.
850 self._run_test(test, test.iterations, test.retries)
Jon Salz1acc8742012-07-17 17:45:55 +0800851
Cheng-Yi Chiangce05c002013-04-04 02:13:17 +0800852 def _run_test(self, test, iterations_left=None, retries_left=None):
Vic Yanga3cecf82014-12-26 00:44:21 -0800853 if not self._ui_initialized and not test.is_no_host():
854 self.init_ui()
Vic Yang08505c72015-01-06 17:01:53 -0800855 invoc = TestInvocation(
Hung-Te Linef7f2be2015-07-20 20:38:51 +0800856 self, test, on_completion=self.invocation_completion,
Claire Changd1961a22015-08-05 16:15:55 +0800857 on_test_failure=lambda: self.test_fail(test))
Jon Salz1acc8742012-07-17 17:45:55 +0800858 new_state = test.update_state(
Ricky Liang48e47f92014-02-26 19:31:51 +0800859 status=TestState.ACTIVE, increment_count=1, error_msg='',
860 invocation=invoc.uuid, iterations_left=iterations_left,
861 retries_left=retries_left,
862 visible=(self.visible_test == test))
Jon Salz1acc8742012-07-17 17:45:55 +0800863 invoc.count = new_state.count
864
865 self.invocations[test] = invoc
866 if self.visible_test is None and test.has_ui:
867 self.set_visible_test(test)
Vic Yang311ddb82012-09-26 12:08:28 +0800868 self.check_exclusive()
Jon Salz1acc8742012-07-17 17:45:55 +0800869 invoc.start()
Jon Salz5f2a0672012-05-22 17:14:06 +0800870
Vic Yang311ddb82012-09-26 12:08:28 +0800871 def check_exclusive(self):
Jon Salzce6a7f82013-06-10 18:22:54 +0800872 # alias since this is really long
873 EXCL_OPT = factory.FactoryTest.EXCLUSIVE_OPTIONS
874
Vic Yang311ddb82012-09-26 12:08:28 +0800875 current_exclusive_items = set([
Jon Salzce6a7f82013-06-10 18:22:54 +0800876 item for item in EXCL_OPT
Vic Yang311ddb82012-09-26 12:08:28 +0800877 if any([test.is_exclusive(item) for test in self.invocations])])
878
879 new_exclusive_items = current_exclusive_items - self.exclusive_items
Jon Salzce6a7f82013-06-10 18:22:54 +0800880 if EXCL_OPT.NETWORKING in new_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800881 logging.info('Disabling network')
882 self.connection_manager.DisableNetworking()
Jon Salzce6a7f82013-06-10 18:22:54 +0800883 if EXCL_OPT.CHARGER in new_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800884 logging.info('Stop controlling charger')
885
886 new_non_exclusive_items = self.exclusive_items - current_exclusive_items
Jon Salzce6a7f82013-06-10 18:22:54 +0800887 if EXCL_OPT.NETWORKING in new_non_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800888 logging.info('Re-enabling network')
889 self.connection_manager.EnableNetworking()
Jon Salzce6a7f82013-06-10 18:22:54 +0800890 if EXCL_OPT.CHARGER in new_non_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800891 logging.info('Start controlling charger')
892
Jon Salzce6a7f82013-06-10 18:22:54 +0800893 if self.cpufreq_manager:
894 enabled = EXCL_OPT.CPUFREQ not in current_exclusive_items
895 try:
896 self.cpufreq_manager.SetEnabled(enabled)
897 except: # pylint: disable=W0702
898 logging.exception('Unable to %s cpufreq services',
899 'enable' if enabled else 'disable')
900
Ricky Liang0f9978e2015-01-30 08:19:17 +0000901 # Only adjust charge state if not excluded
902 if (EXCL_OPT.CHARGER not in current_exclusive_items and
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800903 not sys_utils.InChroot()):
Ricky Liang0f9978e2015-01-30 08:19:17 +0000904 if self.charge_manager:
Cheng-Yi Chiangd8186952013-04-04 23:41:14 +0800905 self.charge_manager.AdjustChargeState()
906 else:
Dean Liao88b93192014-10-23 19:37:41 +0800907 self.charge()
Vic Yang311ddb82012-09-26 12:08:28 +0800908
909 self.exclusive_items = current_exclusive_items
Jon Salz5da61e62012-05-31 13:06:22 +0800910
Dean Liao88b93192014-10-23 19:37:41 +0800911 def charge(self):
912 """Charges the board.
913
914 It won't try again if last time SetChargeState raised an exception.
915 """
916 if not self._can_charge:
917 return
918
919 try:
Ricky Liang9ac35e02015-01-30 16:01:32 +0800920 if self.charge_manager:
921 self.charge_manager.StartCharging()
922 else:
Hung-Te Lin6a72c642015-12-13 22:09:09 +0800923 self.dut.power.SetChargeState(self.dut.power.ChargeState.CHARGE)
Dean Liao88b93192014-10-23 19:37:41 +0800924 except NotImplementedError:
925 logging.info('Charging is not supported')
926 self._can_charge = False
Hung-Te Lin6a72c642015-12-13 22:09:09 +0800927 except dut.DUTException:
Dean Liao88b93192014-10-23 19:37:41 +0800928 logging.exception('Unable to set charge state on this board')
929 self._can_charge = False
930
cychiang21886742012-07-05 15:16:32 +0800931 def check_for_updates(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800932 """Schedules an asynchronous check for updates if necessary."""
cychiang21886742012-07-05 15:16:32 +0800933 if not self.test_list.options.update_period_secs:
934 # Not enabled.
935 return
936
937 now = time.time()
938 if self.last_update_check and (
939 now - self.last_update_check <
940 self.test_list.options.update_period_secs):
941 # Not yet time for another check.
942 return
943
944 self.last_update_check = now
945
946 def handle_check_for_update(reached_shopfloor, md5sum, needs_update):
947 if reached_shopfloor:
948 new_update_md5sum = md5sum if needs_update else None
Hung-Te Line594e5d2015-12-16 02:36:05 +0800949 if self.dut.info.update_md5sum != new_update_md5sum:
cychiang21886742012-07-05 15:16:32 +0800950 logging.info('Received new update MD5SUM: %s', new_update_md5sum)
Hung-Te Line594e5d2015-12-16 02:36:05 +0800951 self.dut.info.Overrides('update_md5sum', new_update_md5sum)
Peter Ammon1e1ec572014-06-26 17:56:32 -0700952 self.run_enqueue(self.update_system_info)
Cheng-Yi Chiang194d3c02015-03-16 14:37:15 +0800953 else:
954 if not self._suppress_periodic_update_messages:
955 logging.warning('Suppress error messages for periodic update checking'
956 ' after the first one.')
957 self._suppress_periodic_update_messages = True
cychiang21886742012-07-05 15:16:32 +0800958
959 updater.CheckForUpdateAsync(
Ricky Liang45c73e72015-01-15 15:00:30 +0800960 handle_check_for_update,
Cheng-Yi Chiang194d3c02015-03-16 14:37:15 +0800961 self.test_list.options.shopfloor_timeout_secs,
962 self._suppress_periodic_update_messages)
cychiang21886742012-07-05 15:16:32 +0800963
Jon Salza6711d72012-07-18 14:33:03 +0800964 def cancel_pending_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800965 """Cancels any tests in the run queue."""
Jon Salza6711d72012-07-18 14:33:03 +0800966 self.run_tests([])
967
Ricky Liang4bff3e32014-02-20 18:46:11 +0800968 def restore_active_run_state(self):
969 """Restores active run id and the list of scheduled tests."""
970 self.run_id = self.state_instance.get_shared_data('run_id', optional=True)
971 self.scheduled_run_tests = self.state_instance.get_shared_data(
972 'scheduled_run_tests', optional=True)
973
974 def set_active_run_state(self):
975 """Sets active run id and the list of scheduled tests."""
976 self.run_id = str(uuid.uuid4())
977 self.scheduled_run_tests = [test.path for test in self.tests_to_run]
978 self.state_instance.set_shared_data('run_id', self.run_id)
979 self.state_instance.set_shared_data('scheduled_run_tests',
980 self.scheduled_run_tests)
981
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +0800982 def run_tests(self, subtrees, status_filter=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800983 """Runs tests under subtree.
Jon Salz258a40c2012-04-19 12:34:01 +0800984
Jon Salz0697cbf2012-07-04 15:14:04 +0800985 The tests are run in order unless one fails (then stops).
986 Backgroundable tests are run simultaneously; when a foreground test is
987 encountered, we wait for all active tests to finish before continuing.
Jon Salzb1b39092012-05-03 02:05:09 +0800988
Ricky Liang6fe218c2013-12-27 15:17:17 +0800989 Args:
990 subtrees: Node or nodes containing tests to run (may either be
991 a single test or a list). Duplicates will be ignored.
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +0800992 status_filter: List of available test states. Only run the tests which
993 states are in the list. Set to None if all test states are available.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800994 """
Hung-Te Lin410f70a2015-12-15 14:53:42 +0800995 self.dut.hooks.OnTestStart()
Vic Yang08505c72015-01-06 17:01:53 -0800996
Jon Salz0697cbf2012-07-04 15:14:04 +0800997 if type(subtrees) != list:
998 subtrees = [subtrees]
Jon Salz258a40c2012-04-19 12:34:01 +0800999
Jon Salz0697cbf2012-07-04 15:14:04 +08001000 # Nodes we've seen so far, to avoid duplicates.
1001 seen = set()
Jon Salz94eb56f2012-06-12 18:01:12 +08001002
Jon Salz0697cbf2012-07-04 15:14:04 +08001003 self.tests_to_run = deque()
1004 for subtree in subtrees:
1005 for test in subtree.walk():
1006 if test in seen:
1007 continue
1008 seen.add(test)
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001009
Jon Salz0697cbf2012-07-04 15:14:04 +08001010 if not test.is_leaf():
1011 continue
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +08001012 if (status_filter is not None and
1013 test.get_state().status not in status_filter):
Jon Salz0697cbf2012-07-04 15:14:04 +08001014 continue
1015 self.tests_to_run.append(test)
Ricky Liang4bff3e32014-02-20 18:46:11 +08001016 if subtrees:
1017 self.set_active_run_state()
Jon Salz0697cbf2012-07-04 15:14:04 +08001018 self.run_next_test()
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001019
Jon Salz0697cbf2012-07-04 15:14:04 +08001020 def reap_completed_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001021 """Removes completed tests from the set of active tests.
Jon Salz0697cbf2012-07-04 15:14:04 +08001022
1023 Also updates the visible test if it was reaped.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001024 """
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001025 test_completed = False
Jon Salz0697cbf2012-07-04 15:14:04 +08001026 for t, v in dict(self.invocations).iteritems():
1027 if v.is_completed():
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001028 test_completed = True
Jon Salz1acc8742012-07-17 17:45:55 +08001029 new_state = t.update_state(**v.update_state_on_completion)
Jon Salz0697cbf2012-07-04 15:14:04 +08001030 del self.invocations[t]
1031
Johny Lin62ed2a32015-05-13 11:57:12 +08001032 # Stop on failure if flag is true and there is no retry chances.
Chun-Ta Lin54e17e42012-09-06 22:05:13 +08001033 if (self.test_list.options.stop_on_failure and
Johny Lin62ed2a32015-05-13 11:57:12 +08001034 new_state.retries_left < 0 and
Chun-Ta Lin54e17e42012-09-06 22:05:13 +08001035 new_state.status == TestState.FAILED):
1036 # Clean all the tests to cause goofy to stop.
1037 self.tests_to_run = []
Ricky Liang45c73e72015-01-15 15:00:30 +08001038 factory.console.info('Stop on failure triggered. Empty the queue.')
Chun-Ta Lin54e17e42012-09-06 22:05:13 +08001039
Jon Salz1acc8742012-07-17 17:45:55 +08001040 if new_state.iterations_left and new_state.status == TestState.PASSED:
1041 # Play it again, Sam!
1042 self._run_test(t)
Cheng-Yi Chiangce05c002013-04-04 02:13:17 +08001043 # new_state.retries_left is obtained after update.
1044 # For retries_left == 0, test can still be run for the last time.
1045 elif (new_state.retries_left >= 0 and
1046 new_state.status == TestState.FAILED):
1047 # Still have to retry, Sam!
1048 self._run_test(t)
Jon Salz1acc8742012-07-17 17:45:55 +08001049
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001050 if test_completed:
Vic Yangf01c59f2013-04-19 17:37:56 +08001051 self.log_watcher.KickWatchThread()
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001052
Jon Salz0697cbf2012-07-04 15:14:04 +08001053 if (self.visible_test is None or
Jon Salz85a39882012-07-05 16:45:04 +08001054 self.visible_test not in self.invocations):
Jon Salz0697cbf2012-07-04 15:14:04 +08001055 self.set_visible_test(None)
1056 # Make the first running test, if any, the visible test
1057 for t in self.test_list.walk():
1058 if t in self.invocations:
1059 self.set_visible_test(t)
1060 break
1061
Jon Salz6dc031d2013-06-19 13:06:23 +08001062 def kill_active_tests(self, abort, root=None, reason=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001063 """Kills and waits for all active tests.
Jon Salz0697cbf2012-07-04 15:14:04 +08001064
Jon Salz85a39882012-07-05 16:45:04 +08001065 Args:
1066 abort: True to change state of killed tests to FAILED, False for
Jon Salz0697cbf2012-07-04 15:14:04 +08001067 UNTESTED.
Jon Salz85a39882012-07-05 16:45:04 +08001068 root: If set, only kills tests with root as an ancestor.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001069 reason: If set, the abort reason.
1070 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001071 self.reap_completed_tests()
1072 for test, invoc in self.invocations.items():
Jon Salz85a39882012-07-05 16:45:04 +08001073 if root and not test.has_ancestor(root):
1074 continue
1075
Ricky Liang45c73e72015-01-15 15:00:30 +08001076 factory.console.info('Killing active test %s...', test.path)
Jon Salz6dc031d2013-06-19 13:06:23 +08001077 invoc.abort_and_join(reason)
Ricky Liang45c73e72015-01-15 15:00:30 +08001078 factory.console.info('Killed %s', test.path)
Jon Salz1acc8742012-07-17 17:45:55 +08001079 test.update_state(**invoc.update_state_on_completion)
Jon Salz0697cbf2012-07-04 15:14:04 +08001080 del self.invocations[test]
Jon Salz1acc8742012-07-17 17:45:55 +08001081
Jon Salz0697cbf2012-07-04 15:14:04 +08001082 if not abort:
1083 test.update_state(status=TestState.UNTESTED)
1084 self.reap_completed_tests()
1085
Jon Salz6dc031d2013-06-19 13:06:23 +08001086 def stop(self, root=None, fail=False, reason=None):
1087 self.kill_active_tests(fail, root, reason)
Jon Salz85a39882012-07-05 16:45:04 +08001088 # Remove any tests in the run queue under the root.
1089 self.tests_to_run = deque([x for x in self.tests_to_run
1090 if root and not x.has_ancestor(root)])
1091 self.run_next_test()
Jon Salz0697cbf2012-07-04 15:14:04 +08001092
Jon Salz4712ac72013-02-07 17:12:05 +08001093 def clear_state(self, root=None):
Jon Salzd7550792013-07-12 05:49:27 +08001094 if root is None:
1095 root = self.test_list
Jon Salz6dc031d2013-06-19 13:06:23 +08001096 self.stop(root, reason='Clearing test state')
Jon Salz4712ac72013-02-07 17:12:05 +08001097 for f in root.walk():
1098 if f.is_leaf():
1099 f.update_state(status=TestState.UNTESTED)
1100
Jon Salz6dc031d2013-06-19 13:06:23 +08001101 def abort_active_tests(self, reason=None):
1102 self.kill_active_tests(True, reason=reason)
Jon Salz0697cbf2012-07-04 15:14:04 +08001103
1104 def main(self):
Jon Salzeff94182013-06-19 15:06:28 +08001105 syslog.openlog('goofy')
1106
Jon Salz0697cbf2012-07-04 15:14:04 +08001107 try:
Jon Salzd7550792013-07-12 05:49:27 +08001108 self.status = Status.INITIALIZING
Jon Salz0697cbf2012-07-04 15:14:04 +08001109 self.init()
1110 self.event_log.Log('goofy_init',
Ricky Liang45c73e72015-01-15 15:00:30 +08001111 success=True)
Jon Salz0697cbf2012-07-04 15:14:04 +08001112 except:
1113 if self.event_log:
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001114 try:
Jon Salz0697cbf2012-07-04 15:14:04 +08001115 self.event_log.Log('goofy_init',
Ricky Liang45c73e72015-01-15 15:00:30 +08001116 success=False,
1117 trace=traceback.format_exc())
Jon Salz0697cbf2012-07-04 15:14:04 +08001118 except: # pylint: disable=W0702
1119 pass
1120 raise
1121
Jon Salzd7550792013-07-12 05:49:27 +08001122 self.status = Status.RUNNING
Jon Salzeff94182013-06-19 15:06:28 +08001123 syslog.syslog('Goofy (factory test harness) starting')
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001124 syslog.syslog('Boot sequence = %d' % GetBootSequence())
Jon Salz0697cbf2012-07-04 15:14:04 +08001125 self.run()
1126
1127 def update_system_info(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001128 """Updates system info."""
Hung-Te Line594e5d2015-12-16 02:36:05 +08001129 info = self.dut.info.GetAll()
1130 self.state_instance.set_shared_data('system_info', info)
Jon Salz0697cbf2012-07-04 15:14:04 +08001131 self.event_client.post_event(Event(Event.Type.SYSTEM_INFO,
Hung-Te Line594e5d2015-12-16 02:36:05 +08001132 system_info=info))
1133 logging.info('System info: %r', info)
Jon Salz0697cbf2012-07-04 15:14:04 +08001134
Jon Salzeb42f0d2012-07-27 19:14:04 +08001135 def update_factory(self, auto_run_on_restart=False, post_update_hook=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001136 """Commences updating factory software.
Jon Salzeb42f0d2012-07-27 19:14:04 +08001137
1138 Args:
1139 auto_run_on_restart: Auto-run when the machine comes back up.
1140 post_update_hook: Code to call after update but immediately before
1141 restart.
1142
1143 Returns:
1144 Never if the update was successful (we just reboot).
1145 False if the update was unnecessary (no update available).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001146 """
Jon Salz6dc031d2013-06-19 13:06:23 +08001147 self.kill_active_tests(False, reason='Factory software update')
Jon Salza6711d72012-07-18 14:33:03 +08001148 self.cancel_pending_tests()
Jon Salz0697cbf2012-07-04 15:14:04 +08001149
Jon Salz5c344f62012-07-13 14:31:16 +08001150 def pre_update_hook():
1151 if auto_run_on_restart:
1152 self.state_instance.set_shared_data('tests_after_shutdown',
1153 FORCE_AUTO_RUN)
1154 self.state_instance.close()
1155
Jon Salzeb42f0d2012-07-27 19:14:04 +08001156 if updater.TryUpdate(pre_update_hook=pre_update_hook):
1157 if post_update_hook:
1158 post_update_hook()
1159 self.env.shutdown('reboot')
Jon Salz0697cbf2012-07-04 15:14:04 +08001160
Ricky Liang8fecf412014-05-22 10:56:14 +08001161 def handle_sigint(self, dummy_signum, dummy_frame): # pylint: disable=W0613
Jon Salz77c151e2012-08-28 07:20:37 +08001162 logging.error('Received SIGINT')
Peter Ammon1e1ec572014-06-26 17:56:32 -07001163 self.run_enqueue(None)
Jon Salz77c151e2012-08-28 07:20:37 +08001164 raise KeyboardInterrupt()
1165
Ricky Liang8fecf412014-05-22 10:56:14 +08001166 def handle_sigterm(self, dummy_signum, dummy_frame): # pylint: disable=W0613
1167 logging.error('Received SIGTERM')
Hung-Te Lin94ca4742014-07-09 20:13:50 +08001168 self.env.terminate()
1169 self.run_queue.put(None)
Ricky Liang8fecf412014-05-22 10:56:14 +08001170 raise RuntimeError('Received SIGTERM')
1171
Jon Salze12c2b32013-06-25 16:24:34 +08001172 def find_kcrashes(self):
1173 """Finds kcrash files, logs them, and marks them as seen."""
1174 seen_crashes = set(
1175 self.state_instance.get_shared_data('seen_crashes', optional=True)
1176 or [])
1177
1178 for path in glob.glob('/var/spool/crash/*'):
1179 if not os.path.isfile(path):
1180 continue
1181 if path in seen_crashes:
1182 continue
1183 try:
1184 stat = os.stat(path)
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001185 mtime = time_utils.TimeString(stat.st_mtime)
Jon Salze12c2b32013-06-25 16:24:34 +08001186 logging.info(
1187 'Found new crash file %s (%d bytes at %s)',
1188 path, stat.st_size, mtime)
1189 extra_log_args = {}
1190
1191 try:
1192 _, ext = os.path.splitext(path)
1193 if ext in ['.kcrash', '.meta']:
1194 ext = ext.replace('.', '')
1195 with open(path) as f:
1196 data = f.read(MAX_CRASH_FILE_SIZE)
1197 tell = f.tell()
1198 logging.info(
1199 'Contents of %s%s:%s',
1200 path,
1201 ('' if tell == stat.st_size
1202 else '(truncated to %d bytes)' % MAX_CRASH_FILE_SIZE),
1203 ('\n' + data).replace('\n', '\n ' + ext + '> '))
1204 extra_log_args['data'] = data
1205
1206 # Copy to /var/factory/kcrash for posterity
1207 kcrash_dir = factory.get_factory_root('kcrash')
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001208 file_utils.TryMakeDirs(kcrash_dir)
Jon Salze12c2b32013-06-25 16:24:34 +08001209 shutil.copy(path, kcrash_dir)
1210 logging.info('Copied to %s',
1211 os.path.join(kcrash_dir, os.path.basename(path)))
1212 finally:
1213 # Even if something goes wrong with the above, still try to
1214 # log to event log
1215 self.event_log.Log('crash_file',
1216 path=path, size=stat.st_size, mtime=mtime,
1217 **extra_log_args)
1218 except: # pylint: disable=W0702
1219 logging.exception('Unable to handle crash files %s', path)
1220 seen_crashes.add(path)
1221
1222 self.state_instance.set_shared_data('seen_crashes', list(seen_crashes))
1223
Jon Salz128b0932013-07-03 16:55:26 +08001224 def GetTestList(self, test_list_id):
1225 """Returns the test list with the given ID.
1226
1227 Raises:
1228 TestListError: The test list ID is not valid.
1229 """
1230 try:
1231 return self.test_lists[test_list_id]
1232 except KeyError:
1233 raise test_lists.TestListError(
1234 '%r is not a valid test list ID (available IDs are [%s])' % (
1235 test_list_id, ', '.join(sorted(self.test_lists.keys()))))
1236
1237 def InitTestLists(self):
1238 """Reads in all test lists and sets the active test list."""
Ricky Liang27051552014-05-04 14:22:26 +08001239 self.test_lists = test_lists.BuildAllTestLists(
1240 force_generic=(self.options.automation_mode is not None))
Jon Salzd7550792013-07-12 05:49:27 +08001241 logging.info('Loaded test lists: [%s]',
1242 test_lists.DescribeTestLists(self.test_lists))
Jon Salz128b0932013-07-03 16:55:26 +08001243
1244 if not self.options.test_list:
1245 self.options.test_list = test_lists.GetActiveTestListId()
1246
1247 if os.sep in self.options.test_list:
1248 # It's a path pointing to an old-style test list; use it.
1249 self.test_list = factory.read_test_list(self.options.test_list)
1250 else:
1251 self.test_list = self.GetTestList(self.options.test_list)
1252
1253 logging.info('Active test list: %s', self.test_list.test_list_id)
1254
1255 if isinstance(self.test_list, test_lists.OldStyleTestList):
1256 # Actually load it in. (See OldStyleTestList for an explanation
1257 # of why this is necessary.)
1258 self.test_list = self.test_list.Load()
1259
1260 self.test_list.state_instance = self.state_instance
1261
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001262 def init_hooks(self):
1263 """Initializes hooks.
1264
1265 Must run after self.test_list ready.
1266 """
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001267 module, cls = self.test_list.options.hooks_class.rsplit('.', 1)
1268 self.hooks = getattr(__import__(module, fromlist=[cls]), cls)()
1269 assert isinstance(self.hooks, factory.Hooks), (
Ricky Liang45c73e72015-01-15 15:00:30 +08001270 'hooks should be of type Hooks but is %r' % type(self.hooks))
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001271 self.hooks.test_list = self.test_list
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001272 self.hooks.OnCreatedTestList()
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001273
Vic Yanga3cecf82014-12-26 00:44:21 -08001274 def init_ui(self):
1275 """Initialize UI."""
1276 self._ui_initialized = True
1277 if self.options.ui == 'chrome':
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001278 if self.options.monolithic:
Hung-Te Lin7bd55312014-12-30 16:43:36 +08001279 self.env.launch_chrome()
1280 else:
1281 # The presenter is responsible for launching Chrome. Let's just
1282 # wait here.
1283 self.env.controller_ready_for_ui()
Vic Yanga3cecf82014-12-26 00:44:21 -08001284 logging.info('Waiting for a web socket connection')
1285 self.web_socket_manager.wait()
1286
1287 # Wait for the test widget size to be set; this is done in
1288 # an asynchronous RPC so there is a small chance that the
1289 # web socket might be opened first.
1290 for _ in range(100): # 10 s
1291 try:
1292 if self.state_instance.get_shared_data('test_widget_size'):
1293 break
1294 except KeyError:
1295 pass # Retry
1296 time.sleep(0.1) # 100 ms
1297 else:
1298 logging.warn('Never received test_widget_size from UI')
1299
Hung-Te Lin7bd55312014-12-30 16:43:36 +08001300 logging.info('Waiting for a web socket connection')
1301 self.web_socket_manager.wait()
1302
Jon Salz0697cbf2012-07-04 15:14:04 +08001303 def init(self, args=None, env=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001304 """Initializes Goofy.
Jon Salz0697cbf2012-07-04 15:14:04 +08001305
1306 Args:
1307 args: A list of command-line arguments. Uses sys.argv if
1308 args is None.
1309 env: An Environment instance to use (or None to choose
1310 FakeChrootEnvironment or DUTEnvironment as appropriate).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001311 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001312 parser = OptionParser()
1313 parser.add_option('-v', '--verbose', dest='verbose',
Jon Salz8fa8e832012-07-13 19:04:09 +08001314 action='store_true',
1315 help='Enable debug logging')
Jon Salz0697cbf2012-07-04 15:14:04 +08001316 parser.add_option('--print_test_list', dest='print_test_list',
Jon Salz8fa8e832012-07-13 19:04:09 +08001317 metavar='FILE',
1318 help='Read and print test list FILE, and exit')
Jon Salz0697cbf2012-07-04 15:14:04 +08001319 parser.add_option('--restart', dest='restart',
Jon Salz8fa8e832012-07-13 19:04:09 +08001320 action='store_true',
1321 help='Clear all test state')
Jon Salz0697cbf2012-07-04 15:14:04 +08001322 parser.add_option('--ui', dest='ui', type='choice',
Jon Salz7b5482e2014-08-04 17:48:41 +08001323 choices=['none', 'chrome'],
Jon Salz2f881df2013-02-01 17:00:35 +08001324 default='chrome',
Jon Salz8fa8e832012-07-13 19:04:09 +08001325 help='UI to use')
Jon Salz0697cbf2012-07-04 15:14:04 +08001326 parser.add_option('--ui_scale_factor', dest='ui_scale_factor',
Jon Salz8fa8e832012-07-13 19:04:09 +08001327 type='int', default=1,
1328 help=('Factor by which to scale UI '
1329 '(Chrome UI only)'))
Jon Salz0697cbf2012-07-04 15:14:04 +08001330 parser.add_option('--test_list', dest='test_list',
Jon Salz8fa8e832012-07-13 19:04:09 +08001331 metavar='FILE',
1332 help='Use FILE as test list')
Jon Salzc79a9982012-08-30 04:42:01 +08001333 parser.add_option('--dummy_shopfloor', action='store_true',
1334 help='Use a dummy shopfloor server')
Hung-Te Lincc41d2a2014-10-29 13:35:20 +08001335 parser.add_option('--dummy_connection_manager', action='store_true',
1336 help='Use a dummy connection manager')
Ricky Liang6fe218c2013-12-27 15:17:17 +08001337 parser.add_option('--automation-mode',
1338 choices=[m.lower() for m in AutomationMode],
Ricky Liang45c73e72015-01-15 15:00:30 +08001339 default='none', help='Factory test automation mode.')
Ricky Liang117484a2014-04-14 11:14:41 +08001340 parser.add_option('--no-auto-run-on-start', dest='auto_run_on_start',
1341 action='store_false', default=True,
1342 help=('do not automatically run the test list on goofy '
1343 'start; this is only valid when factory test '
1344 'automation is enabled'))
Chun-Ta Lina8dd3172014-11-26 16:15:13 +08001345 parser.add_option('--handshake_timeout', dest='handshake_timeout',
1346 type='float', default=0.3,
1347 help=('RPC timeout when doing handshake between device '
1348 'and presenter.'))
Vic Yang7d693c42014-09-14 09:52:39 +08001349 parser.add_option('--standalone', dest='standalone',
1350 action='store_true', default=False,
1351 help=('Assume the presenter is running on the same '
1352 'machines.'))
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001353 parser.add_option('--monolithic', dest='monolithic',
1354 action='store_true', default=False,
1355 help='Run in monolithic mode (without presenter)')
Jon Salz0697cbf2012-07-04 15:14:04 +08001356 (self.options, self.args) = parser.parse_args(args)
1357
Hung-Te Lina846f602014-07-04 20:32:22 +08001358 signal.signal(signal.SIGINT, self.handle_sigint)
1359 # TODO(hungte) SIGTERM does not work properly without Telemetry and should
1360 # be fixed.
Hung-Te Lina846f602014-07-04 20:32:22 +08001361
Jon Salz46b89562012-07-05 11:49:22 +08001362 # Make sure factory directories exist.
1363 factory.get_log_root()
1364 factory.get_state_root()
1365 factory.get_test_data_root()
1366
Jon Salz0697cbf2012-07-04 15:14:04 +08001367 global _inited_logging # pylint: disable=W0603
1368 if not _inited_logging:
1369 factory.init_logging('goofy', verbose=self.options.verbose)
1370 _inited_logging = True
Jon Salz8fa8e832012-07-13 19:04:09 +08001371
Jon Salz0f996602012-10-03 15:26:48 +08001372 if self.options.print_test_list:
Joel Kitchingb85ed7f2014-10-08 18:24:39 +08001373 print(factory.read_test_list(
1374 self.options.print_test_list).__repr__(recursive=True))
Jon Salz0f996602012-10-03 15:26:48 +08001375 sys.exit(0)
1376
Jon Salzee85d522012-07-17 14:34:46 +08001377 event_log.IncrementBootSequence()
Jon Salzd15bbcf2013-05-21 17:33:57 +08001378 # Don't defer logging the initial event, so we can make sure
1379 # that device_id, reimage_id, etc. are all set up.
1380 self.event_log = EventLog('goofy', defer=False)
Jon Salz0697cbf2012-07-04 15:14:04 +08001381
Jon Salz0697cbf2012-07-04 15:14:04 +08001382 if env:
1383 self.env = env
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001384 elif sys_utils.InChroot():
Jon Salz0697cbf2012-07-04 15:14:04 +08001385 self.env = test_environment.FakeChrootEnvironment()
1386 logging.warn(
Ricky Liang45c73e72015-01-15 15:00:30 +08001387 'Using chroot environment: will not actually run autotests')
Hung-Te Lina846f602014-07-04 20:32:22 +08001388 elif self.options.ui == 'chrome':
Ricky Liang09d66d82014-09-25 11:20:54 +08001389 self.env = test_environment.DUTEnvironment()
Jon Salz0697cbf2012-07-04 15:14:04 +08001390 self.env.goofy = self
Vic Yanga4931152014-08-11 16:36:24 -07001391 # web_socket_manager will be initialized later
1392 # pylint: disable=W0108
1393 self.env.has_sockets = lambda: self.web_socket_manager.has_sockets()
Jon Salz0697cbf2012-07-04 15:14:04 +08001394
1395 if self.options.restart:
1396 state.clear_state()
1397
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001398 if self.options.ui_scale_factor != 1 and sys_utils.InQEMU():
Jon Salz0697cbf2012-07-04 15:14:04 +08001399 logging.warn(
Ricky Liang45c73e72015-01-15 15:00:30 +08001400 'In QEMU; ignoring ui_scale_factor argument')
Jon Salz0697cbf2012-07-04 15:14:04 +08001401 self.options.ui_scale_factor = 1
1402
1403 logging.info('Started')
1404
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001405 if not self.options.monolithic:
Hung-Te Lin7bd55312014-12-30 16:43:36 +08001406 self.link_manager = PresenterLinkManager(
1407 check_interval=1,
1408 handshake_timeout=self.options.handshake_timeout,
1409 standalone=self.options.standalone)
Peter Ammon1e1ec572014-06-26 17:56:32 -07001410
Jon Salz0697cbf2012-07-04 15:14:04 +08001411 self.start_state_server()
1412 self.state_instance.set_shared_data('hwid_cfg', get_hwid_cfg())
1413 self.state_instance.set_shared_data('ui_scale_factor',
Ricky Liang09216dc2013-02-22 17:26:45 +08001414 self.options.ui_scale_factor)
Jon Salz0697cbf2012-07-04 15:14:04 +08001415 self.last_shutdown_time = (
Ricky Liang45c73e72015-01-15 15:00:30 +08001416 self.state_instance.get_shared_data('shutdown_time', optional=True))
Jon Salz0697cbf2012-07-04 15:14:04 +08001417 self.state_instance.del_shared_data('shutdown_time', optional=True)
Jon Salzb19ea072013-02-07 16:35:00 +08001418 self.state_instance.del_shared_data('startup_error', optional=True)
Jon Salz0697cbf2012-07-04 15:14:04 +08001419
Ricky Liang6fe218c2013-12-27 15:17:17 +08001420 self.options.automation_mode = ParseAutomationMode(
1421 self.options.automation_mode)
1422 self.state_instance.set_shared_data('automation_mode',
1423 self.options.automation_mode)
1424 self.state_instance.set_shared_data(
1425 'automation_mode_prompt',
1426 AutomationModePrompt[self.options.automation_mode])
1427
Jon Salz128b0932013-07-03 16:55:26 +08001428 try:
1429 self.InitTestLists()
1430 except: # pylint: disable=W0702
1431 logging.exception('Unable to initialize test lists')
1432 self.state_instance.set_shared_data(
1433 'startup_error',
1434 'Unable to initialize test lists\n%s' % (
1435 traceback.format_exc()))
Jon Salzb19ea072013-02-07 16:35:00 +08001436 if self.options.ui == 'chrome':
1437 # Create an empty test list with default options so that the rest of
1438 # startup can proceed.
1439 self.test_list = factory.FactoryTestList(
1440 [], self.state_instance, factory.Options())
1441 else:
1442 # Bail with an error; no point in starting up.
1443 sys.exit('No valid test list; exiting.')
1444
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001445 self.init_hooks()
1446
Jon Salz822838b2013-03-25 17:32:33 +08001447 if self.test_list.options.clear_state_on_start:
1448 self.state_instance.clear_test_state()
1449
Jon Salz670ce062014-05-16 15:53:50 +08001450 # If the phase is invalid, this will raise a ValueError.
1451 phase.SetPersistentPhase(self.test_list.options.phase)
1452
Dean Liao85ca86f2014-11-03 12:28:08 +08001453 # For netboot firmware, mainfw_type should be 'netboot'.
Hung-Te Line594e5d2015-12-16 02:36:05 +08001454 if (self.dut.info.mainfw_type != 'nonchrome' and
1455 self.dut.info.firmware_version is None):
Ricky Liang45c73e72015-01-15 15:00:30 +08001456 self.state_instance.set_shared_data(
1457 'startup_error',
Vic Yang9bd4f772013-06-04 17:34:00 +08001458 'Netboot firmware detected\n'
1459 'Connect Ethernet and reboot to re-image.\n'
1460 u'侦测到网路开机固件\n'
1461 u'请连接乙太网并重启')
1462
Jon Salz0697cbf2012-07-04 15:14:04 +08001463 if not self.state_instance.has_shared_data('ui_lang'):
1464 self.state_instance.set_shared_data('ui_lang',
Ricky Liang45c73e72015-01-15 15:00:30 +08001465 self.test_list.options.ui_lang)
Jon Salz0697cbf2012-07-04 15:14:04 +08001466 self.state_instance.set_shared_data(
Ricky Liang45c73e72015-01-15 15:00:30 +08001467 'test_list_options',
1468 self.test_list.options.__dict__)
Jon Salz0697cbf2012-07-04 15:14:04 +08001469 self.state_instance.test_list = self.test_list
1470
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001471 self.check_log_rotation()
Jon Salz83ef34b2012-11-01 19:46:35 +08001472
Jon Salz23926422012-09-01 03:38:13 +08001473 if self.options.dummy_shopfloor:
Ricky Liang45c73e72015-01-15 15:00:30 +08001474 os.environ[shopfloor.SHOPFLOOR_SERVER_ENV_VAR_NAME] = (
1475 'http://%s:%d/' %
Joel Kitchingb85ed7f2014-10-08 18:24:39 +08001476 (net_utils.LOCALHOST, shopfloor.DEFAULT_SERVER_PORT))
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001477 self.dummy_shopfloor = process_utils.Spawn(
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +08001478 [os.path.join(paths.FACTORY_PATH, 'bin', 'shopfloor_server'),
Jon Salz23926422012-09-01 03:38:13 +08001479 '--dummy'])
1480 elif self.test_list.options.shopfloor_server_url:
1481 shopfloor.set_server_url(self.test_list.options.shopfloor_server_url)
Jon Salz2bf2f6b2013-03-28 18:49:26 +08001482 shopfloor.set_enabled(True)
Jon Salz23926422012-09-01 03:38:13 +08001483
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001484 if self.test_list.options.time_sanitizer and not sys_utils.InChroot():
Jon Salz8fa8e832012-07-13 19:04:09 +08001485 self.time_sanitizer = time_sanitizer.TimeSanitizer(
Ricky Liang45c73e72015-01-15 15:00:30 +08001486 base_time=time_sanitizer.GetBaseTimeFromFile(
1487 # lsb-factory is written by the factory install shim during
1488 # installation, so it should have a good time obtained from
1489 # the mini-Omaha server. If it's not available, we'll use
1490 # /etc/lsb-factory (which will be much older, but reasonably
1491 # sane) and rely on a shopfloor sync to set a more accurate
1492 # time.
1493 '/usr/local/etc/lsb-factory',
1494 '/etc/lsb-release'))
Jon Salz8fa8e832012-07-13 19:04:09 +08001495 self.time_sanitizer.RunOnce()
1496
Vic Yangd8990da2013-06-27 16:57:43 +08001497 if self.test_list.options.check_cpu_usage_period_secs:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001498 self.cpu_usage_watcher = process_utils.Spawn(
Ricky Liang45c73e72015-01-15 15:00:30 +08001499 ['py/tools/cpu_usage_monitor.py', '-p',
1500 str(self.test_list.options.check_cpu_usage_period_secs)],
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +08001501 cwd=paths.FACTORY_PATH)
Vic Yangd8990da2013-06-27 16:57:43 +08001502
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001503 # Enable thermal monitor
1504 if self.test_list.options.thermal_monitor_period_secs > 0:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001505 self.cpu_usage_watcher = process_utils.Spawn(
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001506 ['py/tools/thermal_monitor.py',
1507 '-p', str(self.test_list.options.thermal_monitor_period_secs),
1508 '-d', str(self.test_list.options.thermal_monitor_delta)],
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +08001509 cwd=paths.FACTORY_PATH)
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001510
Jon Salz0697cbf2012-07-04 15:14:04 +08001511 self.init_states()
1512 self.start_event_server()
Wei-Ning Huang38b75f02015-02-25 18:25:14 +08001513 self.start_terminal_server()
Hung-Te Lincc41d2a2014-10-29 13:35:20 +08001514
1515 if self.options.dummy_connection_manager:
1516 # Override network manager creation to dummy implmenetation.
1517 logging.info('Using dummy network manager (--dummy_connection_manager).')
1518 self.connection_manager = connection_manager.DummyConnectionManager()
1519 else:
1520 self.connection_manager = self.env.create_connection_manager(
1521 self.test_list.options.wlans,
Mao Huang4340c632015-04-14 14:35:22 +08001522 self.test_list.options.scan_wifi_period_secs,
1523 self.test_list.options.override_blacklisted_network_devices)
Hung-Te Lincc41d2a2014-10-29 13:35:20 +08001524
Jon Salz0697cbf2012-07-04 15:14:04 +08001525 # Note that we create a log watcher even if
1526 # sync_event_log_period_secs isn't set (no background
1527 # syncing), since we may use it to flush event logs as well.
1528 self.log_watcher = EventLogWatcher(
Ricky Liang45c73e72015-01-15 15:00:30 +08001529 self.test_list.options.sync_event_log_period_secs,
1530 event_log_db_file=None,
1531 handle_event_logs_callback=self.handle_event_logs)
Jon Salz0697cbf2012-07-04 15:14:04 +08001532 if self.test_list.options.sync_event_log_period_secs:
1533 self.log_watcher.StartWatchThread()
1534
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001535 # Creates a system log manager to scan logs periocially.
1536 # A scan includes clearing logs and optionally syncing logs if
1537 # enable_syng_log is True. We kick it to sync logs.
1538 self.system_log_manager = SystemLogManager(
Ricky Liang45c73e72015-01-15 15:00:30 +08001539 sync_log_paths=self.test_list.options.sync_log_paths,
1540 sync_log_period_secs=self.test_list.options.sync_log_period_secs,
1541 scan_log_period_secs=self.test_list.options.scan_log_period_secs,
1542 clear_log_paths=self.test_list.options.clear_log_paths,
1543 clear_log_excluded_paths=self.test_list.options.clear_log_excluded_paths)
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001544 self.system_log_manager.Start()
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +08001545
Jon Salz0697cbf2012-07-04 15:14:04 +08001546 self.update_system_info()
1547
Vic Yang4953fc12012-07-26 16:19:53 +08001548 assert ((self.test_list.options.min_charge_pct is None) ==
1549 (self.test_list.options.max_charge_pct is None))
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001550 if sys_utils.InChroot():
Vic Yange83d9a12013-04-19 20:00:20 +08001551 logging.info('In chroot, ignoring charge manager and charge state')
Ricky Liangc392a1c2014-06-20 18:24:59 +08001552 elif (self.test_list.options.enable_charge_manager and
1553 self.test_list.options.min_charge_pct is not None):
Vic Yang4953fc12012-07-26 16:19:53 +08001554 self.charge_manager = ChargeManager(self.test_list.options.min_charge_pct,
1555 self.test_list.options.max_charge_pct)
Hung-Te Linc17b3d82015-12-15 15:26:08 +08001556 self.dut.status.Overrides('charge_manager', self.charge_manager)
Cheng-Yi Chiangd8186952013-04-04 23:41:14 +08001557 else:
1558 # Goofy should set charger state to charge if charge_manager is disabled.
Dean Liao88b93192014-10-23 19:37:41 +08001559 self.charge()
Vic Yang4953fc12012-07-26 16:19:53 +08001560
Vic Yang6cee2472014-10-22 17:18:52 -07001561 if CoreDumpManager.CoreDumpEnabled():
1562 self.core_dump_manager = CoreDumpManager(
1563 self.test_list.options.core_dump_watchlist)
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001564
Jon Salz0697cbf2012-07-04 15:14:04 +08001565 os.environ['CROS_FACTORY'] = '1'
1566 os.environ['CROS_DISABLE_SITE_SYSINFO'] = '1'
1567
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001568 if not sys_utils.InChroot() and self.test_list.options.use_cpufreq_manager:
Ricky Liangecddbd42014-07-24 11:32:10 +08001569 logging.info('Enabling CPU frequency manager')
Jon Salzddf0d052013-06-18 12:52:44 +08001570 self.cpufreq_manager = CpufreqManager(event_log=self.event_log)
Jon Salzce6a7f82013-06-10 18:22:54 +08001571
Justin Chuang31b02432013-06-27 15:16:51 +08001572 # Startup hooks may want to skip some tests.
1573 self.update_skipped_tests()
Jon Salz416f9cc2013-05-10 18:32:50 +08001574
Jon Salze12c2b32013-06-25 16:24:34 +08001575 self.find_kcrashes()
1576
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001577 # Should not move earlier.
1578 self.hooks.OnStartup()
1579
Ricky Liang36512a32014-07-25 11:47:04 +08001580 # Only after this point the Goofy backend is ready for UI connection.
1581 self.ready_for_ui_connection = True
1582
Ricky Liang650f6bf2012-09-28 13:22:54 +08001583 # Create download path for autotest beforehand or autotests run at
1584 # the same time might fail due to race condition.
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001585 if not sys_utils.InChroot():
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001586 file_utils.TryMakeDirs(os.path.join('/usr/local/autotest', 'tests',
1587 'download'))
Ricky Liang650f6bf2012-09-28 13:22:54 +08001588
Jon Salz0697cbf2012-07-04 15:14:04 +08001589 def state_change_callback(test, test_state):
1590 self.event_client.post_event(
Ricky Liang4bff3e32014-02-20 18:46:11 +08001591 Event(Event.Type.STATE_CHANGE, path=test.path, state=test_state))
Jon Salz0697cbf2012-07-04 15:14:04 +08001592 self.test_list.state_change_callback = state_change_callback
Jon Salz73e0fd02012-04-04 11:46:38 +08001593
Vic Yange2c76a82014-10-30 12:48:19 -07001594 self.autotest_prespawner = prespawner.AutotestPrespawner()
1595 self.autotest_prespawner.start()
1596
1597 self.pytest_prespawner = prespawner.PytestPrespawner()
1598 self.pytest_prespawner.start()
Jon Salza6711d72012-07-18 14:33:03 +08001599
Ricky Liang48e47f92014-02-26 19:31:51 +08001600 tests_after_shutdown = self.state_instance.get_shared_data(
1601 'tests_after_shutdown', optional=True)
Jon Salz57717ca2012-04-04 16:47:25 +08001602
Jon Salz5c344f62012-07-13 14:31:16 +08001603 force_auto_run = (tests_after_shutdown == FORCE_AUTO_RUN)
1604 if not force_auto_run and tests_after_shutdown is not None:
Ricky Liang48e47f92014-02-26 19:31:51 +08001605 logging.info('Resuming tests after shutdown: %s', tests_after_shutdown)
Jon Salz0697cbf2012-07-04 15:14:04 +08001606 self.tests_to_run.extend(
Ricky Liang4bff3e32014-02-20 18:46:11 +08001607 self.test_list.lookup_path(t) for t in tests_after_shutdown)
Peter Ammon1e1ec572014-06-26 17:56:32 -07001608 self.run_enqueue(self.run_next_test)
Jon Salz0697cbf2012-07-04 15:14:04 +08001609 else:
Jon Salz5c344f62012-07-13 14:31:16 +08001610 if force_auto_run or self.test_list.options.auto_run_on_start:
Ricky Liang117484a2014-04-14 11:14:41 +08001611 # If automation mode is enabled, allow suppress auto_run_on_start.
1612 if (self.options.automation_mode == 'NONE' or
1613 self.options.auto_run_on_start):
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +08001614 status_filter = [TestState.UNTESTED]
1615 if self.test_list.options.retry_failed_on_start:
1616 status_filter.append(TestState.FAILED)
1617 self.run_enqueue(lambda: self.run_tests(self.test_list, status_filter))
Jon Salz5c344f62012-07-13 14:31:16 +08001618 self.state_instance.set_shared_data('tests_after_shutdown', None)
Ricky Liang4bff3e32014-02-20 18:46:11 +08001619 self.restore_active_run_state()
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001620
Hung-Te Lin410f70a2015-12-15 14:53:42 +08001621 self.dut.hooks.OnTestStart()
Vic Yang08505c72015-01-06 17:01:53 -08001622
Dean Liao592e4d52013-01-10 20:06:39 +08001623 self.may_disable_cros_shortcut_keys()
1624
1625 def may_disable_cros_shortcut_keys(self):
1626 test_options = self.test_list.options
1627 if test_options.disable_cros_shortcut_keys:
1628 logging.info('Filter ChromeOS shortcut keys.')
1629 self.key_filter = KeyFilter(
1630 unmap_caps_lock=test_options.disable_caps_lock,
1631 caps_lock_keycode=test_options.caps_lock_keycode)
1632 self.key_filter.Start()
1633
Jon Salz0e6532d2012-10-25 16:30:11 +08001634 def _should_sync_time(self, foreground=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001635 """Returns True if we should attempt syncing time with shopfloor.
Jon Salz0e6532d2012-10-25 16:30:11 +08001636
1637 Args:
1638 foreground: If True, synchronizes even if background syncing
1639 is disabled (e.g., in explicit sync requests from the
1640 SyncShopfloor test).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001641 """
Jon Salz0e6532d2012-10-25 16:30:11 +08001642 return ((foreground or
1643 self.test_list.options.sync_time_period_secs) and
Jon Salz54882d02012-08-31 01:57:54 +08001644 self.time_sanitizer and
1645 (not self.time_synced) and
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001646 (not sys_utils.InChroot()))
Jon Salz54882d02012-08-31 01:57:54 +08001647
Jon Salz0e6532d2012-10-25 16:30:11 +08001648 def sync_time_with_shopfloor_server(self, foreground=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001649 """Syncs time with shopfloor server, if not yet synced.
Jon Salz54882d02012-08-31 01:57:54 +08001650
Jon Salz0e6532d2012-10-25 16:30:11 +08001651 Args:
1652 foreground: If True, synchronizes even if background syncing
1653 is disabled (e.g., in explicit sync requests from the
1654 SyncShopfloor test).
1655
Jon Salz54882d02012-08-31 01:57:54 +08001656 Returns:
1657 False if no time sanitizer is available, or True if this sync (or a
1658 previous sync) succeeded.
1659
1660 Raises:
1661 Exception if unable to contact the shopfloor server.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001662 """
Jon Salz0e6532d2012-10-25 16:30:11 +08001663 if self._should_sync_time(foreground):
Jon Salz54882d02012-08-31 01:57:54 +08001664 self.time_sanitizer.SyncWithShopfloor()
1665 self.time_synced = True
1666 return self.time_synced
1667
Jon Salzb92c5112012-09-21 15:40:11 +08001668 def log_disk_space_stats(self):
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001669 if (sys_utils.InChroot() or
Jon Salz18e0e022013-06-11 17:13:39 +08001670 not self.test_list.options.log_disk_space_period_secs):
Jon Salzb92c5112012-09-21 15:40:11 +08001671 return
1672
1673 now = time.time()
1674 if (self.last_log_disk_space_time and
1675 now - self.last_log_disk_space_time <
1676 self.test_list.options.log_disk_space_period_secs):
1677 return
1678 self.last_log_disk_space_time = now
1679
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001680 # Upload event if stateful partition usage is above threshold.
1681 # Stateful partition is mounted on /usr/local, while
1682 # encrypted stateful partition is mounted on /var.
1683 # If there are too much logs in the factory process,
1684 # these two partitions might get full.
Jon Salzb92c5112012-09-21 15:40:11 +08001685 try:
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001686 vfs_infos = disk_space.GetAllVFSInfo()
1687 stateful_info, encrypted_info = None, None
1688 for vfs_info in vfs_infos.values():
1689 if '/usr/local' in vfs_info.mount_points:
1690 stateful_info = vfs_info
1691 if '/var' in vfs_info.mount_points:
1692 encrypted_info = vfs_info
1693
1694 stateful = disk_space.GetPartitionUsage(stateful_info)
1695 encrypted = disk_space.GetPartitionUsage(encrypted_info)
1696
Ricky Liang45c73e72015-01-15 15:00:30 +08001697 above_threshold = (
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001698 self.test_list.options.stateful_usage_threshold and
1699 max(stateful.bytes_used_pct,
1700 stateful.inodes_used_pct,
1701 encrypted.bytes_used_pct,
1702 encrypted.inodes_used_pct) >
Ricky Liang45c73e72015-01-15 15:00:30 +08001703 self.test_list.options.stateful_usage_threshold)
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001704
1705 if above_threshold:
1706 self.event_log.Log('stateful_partition_usage',
Ricky Liang45c73e72015-01-15 15:00:30 +08001707 partitions={
1708 'stateful': {
1709 'bytes_used_pct': FloatDigit(stateful.bytes_used_pct, 2),
1710 'inodes_used_pct': FloatDigit(stateful.inodes_used_pct, 2)},
1711 'encrypted_stateful': {
1712 'bytes_used_pct': FloatDigit(encrypted.bytes_used_pct, 2),
1713 'inodes_used_pct': FloatDigit(encrypted.inodes_used_pct, 2)}
1714 })
Cheng-Yi Chiang1b722322015-03-16 20:07:03 +08001715 self.log_watcher.KickWatchThread()
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001716 if (not sys_utils.InChroot() and
Cheng-Yi Chiang00798e72013-06-20 18:16:39 +08001717 self.test_list.options.stateful_usage_above_threshold_action):
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001718 process_utils.Spawn(
1719 self.test_list.options.stateful_usage_above_threshold_action,
1720 call=True)
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001721
1722 message = disk_space.FormatSpaceUsedAll(vfs_infos)
Jon Salz3c493bb2013-02-07 17:24:58 +08001723 if message != self.last_log_disk_space_message:
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001724 if above_threshold:
1725 logging.warning(message)
1726 else:
1727 logging.info(message)
Jon Salz3c493bb2013-02-07 17:24:58 +08001728 self.last_log_disk_space_message = message
Jon Salzb92c5112012-09-21 15:40:11 +08001729 except: # pylint: disable=W0702
1730 logging.exception('Unable to get disk space used')
1731
Justin Chuang83813982013-05-13 01:26:32 +08001732 def check_battery(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001733 """Checks the current battery status.
Justin Chuang83813982013-05-13 01:26:32 +08001734
1735 Logs current battery charging level and status to log. If the battery level
1736 is lower below warning_low_battery_pct, send warning event to shopfloor.
1737 If the battery level is lower below critical_low_battery_pct, flush disks.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001738 """
Justin Chuang83813982013-05-13 01:26:32 +08001739 if not self.test_list.options.check_battery_period_secs:
1740 return
1741
1742 now = time.time()
1743 if (self.last_check_battery_time and
1744 now - self.last_check_battery_time <
1745 self.test_list.options.check_battery_period_secs):
1746 return
1747 self.last_check_battery_time = now
1748
1749 message = ''
1750 log_level = logging.INFO
1751 try:
Hung-Te Lin6a72c642015-12-13 22:09:09 +08001752 power = self.dut.power
Justin Chuang83813982013-05-13 01:26:32 +08001753 if not power.CheckBatteryPresent():
1754 message = 'Battery is not present'
1755 else:
1756 ac_present = power.CheckACPresent()
1757 charge_pct = power.GetChargePct(get_float=True)
1758 message = ('Current battery level %.1f%%, AC charger is %s' %
1759 (charge_pct, 'connected' if ac_present else 'disconnected'))
1760
1761 if charge_pct > self.test_list.options.critical_low_battery_pct:
1762 critical_low_battery = False
1763 else:
1764 critical_low_battery = True
1765 # Only sync disks when battery level is still above minimum
1766 # value. This can be used for offline analysis when shopfloor cannot
1767 # be connected.
1768 if charge_pct > MIN_BATTERY_LEVEL_FOR_DISK_SYNC:
1769 logging.warning('disk syncing for critical low battery situation')
1770 os.system('sync; sync; sync')
1771 else:
1772 logging.warning('disk syncing is cancelled '
1773 'because battery level is lower than %.1f',
1774 MIN_BATTERY_LEVEL_FOR_DISK_SYNC)
1775
1776 # Notify shopfloor server
1777 if (critical_low_battery or
1778 (not ac_present and
1779 charge_pct <= self.test_list.options.warning_low_battery_pct)):
1780 log_level = logging.WARNING
1781
1782 self.event_log.Log('low_battery',
1783 battery_level=charge_pct,
1784 charger_connected=ac_present,
1785 critical=critical_low_battery)
1786 self.log_watcher.KickWatchThread()
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001787 if self.test_list.options.enable_sync_log:
1788 self.system_log_manager.KickToSync()
Ricky Liang45c73e72015-01-15 15:00:30 +08001789 except: # pylint: disable=W0702
Justin Chuang83813982013-05-13 01:26:32 +08001790 logging.exception('Unable to check battery or notify shopfloor')
1791 finally:
1792 if message != self.last_check_battery_message:
1793 logging.log(log_level, message)
1794 self.last_check_battery_message = message
1795
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001796 def check_core_dump(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001797 """Checks if there is any core dumped file.
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001798
1799 Removes unwanted core dump files immediately.
1800 Syncs those files matching watch list to server with a delay between
1801 each sync. After the files have been synced to server, deletes the files.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001802 """
Vic Yang6cee2472014-10-22 17:18:52 -07001803 if not self.core_dump_manager:
1804 return
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001805 core_dump_files = self.core_dump_manager.ScanFiles()
1806 if core_dump_files:
1807 now = time.time()
1808 if (self.last_kick_sync_time and now - self.last_kick_sync_time <
1809 self.test_list.options.kick_sync_min_interval_secs):
1810 return
1811 self.last_kick_sync_time = now
1812
1813 # Sends event to server
1814 self.event_log.Log('core_dumped', files=core_dump_files)
1815 self.log_watcher.KickWatchThread()
1816
1817 # Syncs files to server
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001818 if self.test_list.options.enable_sync_log:
1819 self.system_log_manager.KickToSync(
Cheng-Yi Chiangd3516a32013-07-17 15:30:47 +08001820 core_dump_files, self.core_dump_manager.ClearFiles)
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001821
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001822 def check_log_rotation(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001823 """Checks log rotation file presence/absence according to test_list option.
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001824
1825 Touch /var/lib/cleanup_logs_paused if test_list.options.disable_log_rotation
1826 is True, delete it otherwise. This must be done in idle loop because
1827 autotest client will touch /var/lib/cleanup_logs_paused each time it runs
1828 an autotest.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001829 """
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001830 if sys_utils.InChroot():
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001831 return
1832 try:
1833 if self.test_list.options.disable_log_rotation:
1834 open(CLEANUP_LOGS_PAUSED, 'w').close()
1835 else:
1836 file_utils.TryUnlink(CLEANUP_LOGS_PAUSED)
1837 except: # pylint: disable=W0702
1838 # Oh well. Logs an error (but no trace)
1839 logging.info(
1840 'Unable to %s %s: %s',
1841 'touch' if self.test_list.options.disable_log_rotation else 'delete',
Hung-Te Linf707b242016-01-08 23:11:42 +08001842 CLEANUP_LOGS_PAUSED, debug_utils.FormatExceptionOnly())
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001843
Jon Salz8fa8e832012-07-13 19:04:09 +08001844 def sync_time_in_background(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001845 """Writes out current time and tries to sync with shopfloor server."""
Jon Salzb22d1172012-08-06 10:38:57 +08001846 if not self.time_sanitizer:
1847 return
1848
1849 # Write out the current time.
1850 self.time_sanitizer.SaveTime()
1851
Jon Salz54882d02012-08-31 01:57:54 +08001852 if not self._should_sync_time():
Jon Salz8fa8e832012-07-13 19:04:09 +08001853 return
1854
1855 now = time.time()
1856 if self.last_sync_time and (
1857 now - self.last_sync_time <
1858 self.test_list.options.sync_time_period_secs):
1859 # Not yet time for another check.
1860 return
1861 self.last_sync_time = now
1862
1863 def target():
1864 try:
Jon Salz54882d02012-08-31 01:57:54 +08001865 self.sync_time_with_shopfloor_server()
Jon Salz8fa8e832012-07-13 19:04:09 +08001866 except: # pylint: disable=W0702
1867 # Oh well. Log an error (but no trace)
1868 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +08001869 'Unable to get time from shopfloor server: %s',
Hung-Te Linf707b242016-01-08 23:11:42 +08001870 debug_utils.FormatExceptionOnly())
Jon Salz8fa8e832012-07-13 19:04:09 +08001871
1872 thread = threading.Thread(target=target)
1873 thread.daemon = True
1874 thread.start()
1875
Peter Ammon1e1ec572014-06-26 17:56:32 -07001876 def perform_periodic_tasks(self):
1877 """Override of base method to perform periodic work.
Vic Yang4953fc12012-07-26 16:19:53 +08001878
Peter Ammon1e1ec572014-06-26 17:56:32 -07001879 This method must not raise exceptions.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001880 """
Peter Ammon1e1ec572014-06-26 17:56:32 -07001881 super(Goofy, self).perform_periodic_tasks()
Jon Salzb22d1172012-08-06 10:38:57 +08001882
Vic Yang311ddb82012-09-26 12:08:28 +08001883 self.check_exclusive()
cychiang21886742012-07-05 15:16:32 +08001884 self.check_for_updates()
Jon Salz8fa8e832012-07-13 19:04:09 +08001885 self.sync_time_in_background()
Jon Salzb92c5112012-09-21 15:40:11 +08001886 self.log_disk_space_stats()
Justin Chuang83813982013-05-13 01:26:32 +08001887 self.check_battery()
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001888 self.check_core_dump()
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001889 self.check_log_rotation()
Jon Salz57717ca2012-04-04 16:47:25 +08001890
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001891 def handle_event_logs(self, chunks, periodic=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001892 """Callback for event watcher.
Jon Salz258a40c2012-04-19 12:34:01 +08001893
Jon Salz0697cbf2012-07-04 15:14:04 +08001894 Attempts to upload the event logs to the shopfloor server.
Vic Yang93027612013-05-06 02:42:49 +08001895
1896 Args:
Jon Salzd15bbcf2013-05-21 17:33:57 +08001897 chunks: A list of Chunk objects.
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001898 periodic: This event log handling is periodic. Error messages
1899 will only be shown for the first time.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001900 """
Vic Yang93027612013-05-06 02:42:49 +08001901 first_exception = None
1902 exception_count = 0
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001903 # Suppress error messages for periodic event syncing except for the
1904 # first time. If event syncing is not periodic, always show the error
1905 # messages.
1906 quiet = self._suppress_event_log_error_messages if periodic else False
Vic Yang93027612013-05-06 02:42:49 +08001907
Jon Salzd15bbcf2013-05-21 17:33:57 +08001908 for chunk in chunks:
Vic Yang93027612013-05-06 02:42:49 +08001909 try:
Jon Salzcddb6402013-05-23 12:56:42 +08001910 description = 'event logs (%s)' % str(chunk)
Vic Yang93027612013-05-06 02:42:49 +08001911 start_time = time.time()
1912 shopfloor_client = shopfloor.get_instance(
Ricky Liang45c73e72015-01-15 15:00:30 +08001913 detect=True,
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001914 timeout=self.test_list.options.shopfloor_timeout_secs,
1915 quiet=quiet)
Ricky Liang45c73e72015-01-15 15:00:30 +08001916 shopfloor_client.UploadEvent(chunk.log_name + '.' +
Jon Salzd15bbcf2013-05-21 17:33:57 +08001917 event_log.GetReimageId(),
1918 Binary(chunk.chunk))
Vic Yang93027612013-05-06 02:42:49 +08001919 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +08001920 'Successfully synced %s in %.03f s',
1921 description, time.time() - start_time)
1922 except: # pylint: disable=W0702
Hung-Te Linf707b242016-01-08 23:11:42 +08001923 first_exception = (first_exception or
1924 (chunk.log_name + ': ' +
1925 debug_utils.FormatExceptionOnly()))
Vic Yang93027612013-05-06 02:42:49 +08001926 exception_count += 1
1927
1928 if exception_count:
1929 if exception_count == 1:
1930 msg = 'Log upload failed: %s' % first_exception
1931 else:
1932 msg = '%d log upload failed; first is: %s' % (
1933 exception_count, first_exception)
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001934 # For periodic event log syncing, only show the first error messages.
1935 if periodic:
1936 if not self._suppress_event_log_error_messages:
1937 self._suppress_event_log_error_messages = True
1938 logging.warning('Suppress periodic shopfloor error messages for '
1939 'event log syncing after the first one.')
1940 raise Exception(msg)
1941 # For event log syncing by request, show the error messages.
1942 else:
1943 raise Exception(msg)
Vic Yang93027612013-05-06 02:42:49 +08001944
Ricky Liang45c73e72015-01-15 15:00:30 +08001945 def run_tests_with_status(self, statuses_to_run, starting_at=None, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001946 """Runs all top-level tests with a particular status.
Jon Salz0405ab52012-03-16 15:26:52 +08001947
Jon Salz0697cbf2012-07-04 15:14:04 +08001948 All active tests, plus any tests to re-run, are reset.
Jon Salz57717ca2012-04-04 16:47:25 +08001949
Jon Salz0697cbf2012-07-04 15:14:04 +08001950 Args:
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001951 statuses_to_run: The particular status that caller wants to run.
Jon Salz0697cbf2012-07-04 15:14:04 +08001952 starting_at: If provided, only auto-runs tests beginning with
1953 this test.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001954 root: The root of tests to run. If not provided, it will be
1955 the root of all tests.
1956 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001957 root = root or self.test_list
Jon Salz57717ca2012-04-04 16:47:25 +08001958
Jon Salz0697cbf2012-07-04 15:14:04 +08001959 if starting_at:
1960 # Make sure they passed a test, not a string.
1961 assert isinstance(starting_at, factory.FactoryTest)
Jon Salz0405ab52012-03-16 15:26:52 +08001962
Jon Salz0697cbf2012-07-04 15:14:04 +08001963 tests_to_reset = []
1964 tests_to_run = []
Jon Salz0405ab52012-03-16 15:26:52 +08001965
Jon Salz0697cbf2012-07-04 15:14:04 +08001966 found_starting_at = False
Jon Salz0405ab52012-03-16 15:26:52 +08001967
Jon Salz0697cbf2012-07-04 15:14:04 +08001968 for test in root.get_top_level_tests():
1969 if starting_at:
1970 if test == starting_at:
1971 # We've found starting_at; do auto-run on all
1972 # subsequent tests.
1973 found_starting_at = True
1974 if not found_starting_at:
1975 # Don't start this guy yet
1976 continue
Jon Salz0405ab52012-03-16 15:26:52 +08001977
Jon Salz0697cbf2012-07-04 15:14:04 +08001978 status = test.get_state().status
1979 if status == TestState.ACTIVE or status in statuses_to_run:
1980 # Reset the test (later; we will need to abort
1981 # all active tests first).
1982 tests_to_reset.append(test)
1983 if status in statuses_to_run:
1984 tests_to_run.append(test)
Jon Salz0405ab52012-03-16 15:26:52 +08001985
Jon Salz6dc031d2013-06-19 13:06:23 +08001986 self.abort_active_tests('Operator requested run/re-run of certain tests')
Jon Salz258a40c2012-04-19 12:34:01 +08001987
Jon Salz0697cbf2012-07-04 15:14:04 +08001988 # Reset all statuses of the tests to run (in case any tests were active;
1989 # we want them to be run again).
1990 for test_to_reset in tests_to_reset:
1991 for test in test_to_reset.walk():
1992 test.update_state(status=TestState.UNTESTED)
Jon Salz57717ca2012-04-04 16:47:25 +08001993
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +08001994 self.run_tests(tests_to_run, [TestState.UNTESTED])
Jon Salz0405ab52012-03-16 15:26:52 +08001995
Jon Salz0697cbf2012-07-04 15:14:04 +08001996 def restart_tests(self, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001997 """Restarts all tests."""
Jon Salz0697cbf2012-07-04 15:14:04 +08001998 root = root or self.test_list
Jon Salz0405ab52012-03-16 15:26:52 +08001999
Jon Salz6dc031d2013-06-19 13:06:23 +08002000 self.abort_active_tests('Operator requested restart of certain tests')
Jon Salz0697cbf2012-07-04 15:14:04 +08002001 for test in root.walk():
Ricky Liangfea4ac92014-08-21 11:55:59 +08002002 test.update_state(status=TestState.UNTESTED)
Jon Salz0697cbf2012-07-04 15:14:04 +08002003 self.run_tests(root)
Hung-Te Lin96632362012-03-20 21:14:18 +08002004
Jon Salz0697cbf2012-07-04 15:14:04 +08002005 def auto_run(self, starting_at=None, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002006 """"Auto-runs" tests that have not been run yet.
Hung-Te Lin96632362012-03-20 21:14:18 +08002007
Jon Salz0697cbf2012-07-04 15:14:04 +08002008 Args:
2009 starting_at: If provide, only auto-runs tests beginning with
2010 this test.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002011 root: If provided, the root of tests to run. If not provided, the root
2012 will be test_list (root of all tests).
2013 """
Jon Salz0697cbf2012-07-04 15:14:04 +08002014 root = root or self.test_list
2015 self.run_tests_with_status([TestState.UNTESTED, TestState.ACTIVE],
Ricky Liang45c73e72015-01-15 15:00:30 +08002016 starting_at=starting_at,
2017 root=root)
Jon Salz968e90b2012-03-18 16:12:43 +08002018
Jon Salz0697cbf2012-07-04 15:14:04 +08002019 def re_run_failed(self, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002020 """Re-runs failed tests."""
Jon Salz0697cbf2012-07-04 15:14:04 +08002021 root = root or self.test_list
2022 self.run_tests_with_status([TestState.FAILED], root=root)
Jon Salz57717ca2012-04-04 16:47:25 +08002023
Jon Salz0697cbf2012-07-04 15:14:04 +08002024 def show_review_information(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002025 """Event handler for showing review information screen.
Jon Salz57717ca2012-04-04 16:47:25 +08002026
Peter Ammon1e1ec572014-06-26 17:56:32 -07002027 The information screen is rendered by main UI program (ui.py), so in
Jon Salz0697cbf2012-07-04 15:14:04 +08002028 goofy we only need to kill all active tests, set them as untested, and
2029 clear remaining tests.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002030 """
Jon Salz0697cbf2012-07-04 15:14:04 +08002031 self.kill_active_tests(False)
Jon Salza6711d72012-07-18 14:33:03 +08002032 self.cancel_pending_tests()
Jon Salz57717ca2012-04-04 16:47:25 +08002033
Jon Salz0697cbf2012-07-04 15:14:04 +08002034 def handle_switch_test(self, event):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002035 """Switches to a particular test.
Jon Salz0405ab52012-03-16 15:26:52 +08002036
Ricky Liang6fe218c2013-12-27 15:17:17 +08002037 Args:
2038 event: The SWITCH_TEST event.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002039 """
Jon Salz0697cbf2012-07-04 15:14:04 +08002040 test = self.test_list.lookup_path(event.path)
2041 if not test:
2042 logging.error('Unknown test %r', event.key)
2043 return
Jon Salz73e0fd02012-04-04 11:46:38 +08002044
Jon Salz0697cbf2012-07-04 15:14:04 +08002045 invoc = self.invocations.get(test)
2046 if invoc and test.backgroundable:
2047 # Already running: just bring to the front if it
2048 # has a UI.
2049 logging.info('Setting visible test to %s', test.path)
Jon Salz36fbbb52012-07-05 13:45:06 +08002050 self.set_visible_test(test)
Jon Salz0697cbf2012-07-04 15:14:04 +08002051 return
Jon Salz73e0fd02012-04-04 11:46:38 +08002052
Jon Salz6dc031d2013-06-19 13:06:23 +08002053 self.abort_active_tests('Operator requested abort (switch_test)')
Jon Salz0697cbf2012-07-04 15:14:04 +08002054 for t in test.walk():
2055 t.update_state(status=TestState.UNTESTED)
Jon Salz73e0fd02012-04-04 11:46:38 +08002056
Jon Salz0697cbf2012-07-04 15:14:04 +08002057 if self.test_list.options.auto_run_on_keypress:
2058 self.auto_run(starting_at=test)
2059 else:
2060 self.run_tests(test)
Jon Salz73e0fd02012-04-04 11:46:38 +08002061
Wei-Ning Huang38b75f02015-02-25 18:25:14 +08002062 def handle_key_filter_mode(self, event):
2063 if self.key_filter:
2064 if getattr(event, 'enabled'):
2065 self.key_filter.Start()
2066 else:
2067 self.key_filter.Stop()
2068
Jon Salz0697cbf2012-07-04 15:14:04 +08002069 def wait(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002070 """Waits for all pending invocations.
Jon Salz0697cbf2012-07-04 15:14:04 +08002071
2072 Useful for testing.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002073 """
Jon Salz1acc8742012-07-17 17:45:55 +08002074 while self.invocations:
2075 for k, v in self.invocations.iteritems():
2076 logging.info('Waiting for %s to complete...', k)
2077 v.thread.join()
2078 self.reap_completed_tests()
Jon Salz0697cbf2012-07-04 15:14:04 +08002079
Claire Changd1961a22015-08-05 16:15:55 +08002080 def test_fail(self, test):
Hung-Te Lin410f70a2015-12-15 14:53:42 +08002081 self.dut.hooks.OnTestFailure(test)
Claire Changd1961a22015-08-05 16:15:55 +08002082 if self.link_manager:
2083 self.link_manager.UpdateStatus(False)
2084
Hung-Te Linf2f78f72012-02-08 19:27:11 +08002085if __name__ == '__main__':
Peter Ammona3d298c2014-09-23 10:11:02 -07002086 Goofy.run_main_and_exit()