blob: e665d8307ae24dc1b73580643f05a86467751388 [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
Wei-Han Chene8a025f2016-01-14 16:42:02 +080048from cros.factory.test.dut import utils as dut_utils
Ricky Liang6fe218c2013-12-27 15:17:17 +080049from cros.factory.test.e2e_test.common import (
50 AutomationMode, AutomationModePrompt, ParseAutomationMode)
Jon Salz83591782012-06-26 11:09:58 +080051from cros.factory.test.event import Event
52from cros.factory.test.event import EventClient
53from cros.factory.test.event import EventServer
Hung-Te Lin91492a12014-11-25 18:56:30 +080054from cros.factory.test.event_log_watcher import EventLogWatcher
jcliangcd688182012-08-20 21:01:26 +080055from cros.factory.test.factory import TestState
Hung-Te Lin3f096842016-01-13 17:37:06 +080056from cros.factory.test.rules import phase
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +080057from cros.factory.test.test_lists import test_lists
Hung-Te Linc367ac02015-12-22 19:33:23 +080058from cros.factory.test.utils.charge_manager import ChargeManager
59from cros.factory.test.utils.core_dump_manager import CoreDumpManager
60from cros.factory.test.utils.cpufreq_manager import CpufreqManager
Dean Liao592e4d52013-01-10 20:06:39 +080061from cros.factory.tools.key_filter import KeyFilter
Hung-Te Lind3ee0102015-12-28 17:21:50 +080062from cros.factory.tools import disk_space
Hung-Te Linf707b242016-01-08 23:11:42 +080063from cros.factory.utils import debug_utils
Jon Salz2af235d2013-06-24 14:47:21 +080064from cros.factory.utils import file_utils
Joel Kitchingb85ed7f2014-10-08 18:24:39 +080065from cros.factory.utils import net_utils
Hung-Te Lin4e6357c2016-01-08 14:32:00 +080066from cros.factory.utils import process_utils
67from cros.factory.utils import sys_utils
68from cros.factory.utils import time_utils
Hung-Te Linf707b242016-01-08 23:11:42 +080069from cros.factory.utils import type_utils
Hung-Te Linf2f78f72012-02-08 19:27:11 +080070
71
Hung-Te Linf2f78f72012-02-08 19:27:11 +080072HWID_CFG_PATH = '/usr/local/share/chromeos-hwid/cfg'
Ricky Liang45c73e72015-01-15 15:00:30 +080073CACHES_DIR = os.path.join(factory.get_state_root(), 'caches')
Hung-Te Linf2f78f72012-02-08 19:27:11 +080074
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +080075CLEANUP_LOGS_PAUSED = '/var/lib/cleanup_logs_paused'
76
Jon Salz5c344f62012-07-13 14:31:16 +080077# Value for tests_after_shutdown that forces auto-run (e.g., after
78# a factory update, when the available set of tests might change).
79FORCE_AUTO_RUN = 'force_auto_run'
80
Justin Chuang83813982013-05-13 01:26:32 +080081# Sync disks when battery level is higher than this value.
82# Otherwise, power loss during disk sync operation may incur even worse outcome.
83MIN_BATTERY_LEVEL_FOR_DISK_SYNC = 1.0
84
Ricky Liang45c73e72015-01-15 15:00:30 +080085MAX_CRASH_FILE_SIZE = 64 * 1024
Jon Salze12c2b32013-06-25 16:24:34 +080086
Hung-Te Linf707b242016-01-08 23:11:42 +080087Status = type_utils.Enum(['UNINITIALIZED', 'INITIALIZING', 'RUNNING',
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +080088 'TERMINATING', 'TERMINATED'])
Jon Salzd7550792013-07-12 05:49:27 +080089
Ricky Liang45c73e72015-01-15 15:00:30 +080090
Hung-Te Linf2f78f72012-02-08 19:27:11 +080091def get_hwid_cfg():
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +080092 """Returns the HWID config tag, or an empty string if none can be found."""
Jon Salz0697cbf2012-07-04 15:14:04 +080093 if 'CROS_HWID' in os.environ:
94 return os.environ['CROS_HWID']
95 if os.path.exists(HWID_CFG_PATH):
Ricky Liang45c73e72015-01-15 15:00:30 +080096 with open(HWID_CFG_PATH, 'r') as hwid_cfg_handle:
Jon Salz0697cbf2012-07-04 15:14:04 +080097 return hwid_cfg_handle.read().strip()
98 return ''
Hung-Te Linf2f78f72012-02-08 19:27:11 +080099
100
Jon Salz73e0fd02012-04-04 11:46:38 +0800101_inited_logging = False
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800102
Ricky Liang45c73e72015-01-15 15:00:30 +0800103
Peter Ammon1e1ec572014-06-26 17:56:32 -0700104class Goofy(GoofyBase):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800105 """The main factory flow.
Jon Salz0697cbf2012-07-04 15:14:04 +0800106
107 Note that all methods in this class must be invoked from the main
108 (event) thread. Other threads, such as callbacks and TestInvocation
109 methods, should instead post events on the run queue.
110
111 TODO: Unit tests. (chrome-os-partner:7409)
112
113 Properties:
114 uuid: A unique UUID for this invocation of Goofy.
115 state_instance: An instance of FactoryState.
116 state_server: The FactoryState XML/RPC server.
117 state_server_thread: A thread running state_server.
118 event_server: The EventServer socket server.
119 event_server_thread: A thread running event_server.
120 event_client: A client to the event server.
121 connection_manager: The connection_manager object.
Cheng-Yi Chiang835f2682013-05-06 22:15:48 +0800122 system_log_manager: The SystemLogManager object.
123 core_dump_manager: The CoreDumpManager object.
Jon Salz0697cbf2012-07-04 15:14:04 +0800124 ui_process: The factory ui process object.
Jon Salz0697cbf2012-07-04 15:14:04 +0800125 invocations: A map from FactoryTest objects to the corresponding
126 TestInvocations objects representing active tests.
127 tests_to_run: A deque of tests that should be run when the current
128 test(s) complete.
129 options: Command-line options.
130 args: Command-line args.
131 test_list: The test list.
Jon Salz128b0932013-07-03 16:55:26 +0800132 test_lists: All new-style test lists.
Ricky Liang4bff3e32014-02-20 18:46:11 +0800133 run_id: The identifier for latest test run.
134 scheduled_run_tests: The list of tests scheduled for latest test run.
Jon Salz0697cbf2012-07-04 15:14:04 +0800135 event_handlers: Map of Event.Type to the method used to handle that
136 event. If the method has an 'event' argument, the event is passed
137 to the handler.
Jon Salz3c493bb2013-02-07 17:24:58 +0800138 last_log_disk_space_message: The last message we logged about disk space
139 (to avoid duplication).
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +0800140 last_kick_sync_time: The last time to kick system_log_manager to sync
141 because of core dump files (to avoid kicking too soon then abort the
142 sync.)
Jon Salz416f9cc2013-05-10 18:32:50 +0800143 hooks: A Hooks object containing hooks for various Goofy actions.
Jon Salzd7550792013-07-12 05:49:27 +0800144 status: The current Goofy status (a member of the Status enum).
Peter Ammon948b7172014-07-15 12:43:06 -0700145 link_manager: Instance of PresenterLinkManager for communicating
146 with GoofyPresenter
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800147 """
Ricky Liang45c73e72015-01-15 15:00:30 +0800148
Jon Salz0697cbf2012-07-04 15:14:04 +0800149 def __init__(self):
Peter Ammon1e1ec572014-06-26 17:56:32 -0700150 super(Goofy, self).__init__()
Jon Salz0697cbf2012-07-04 15:14:04 +0800151 self.uuid = str(uuid.uuid4())
152 self.state_instance = None
153 self.state_server = None
154 self.state_server_thread = None
Jon Salz16d10542012-07-23 12:18:45 +0800155 self.goofy_rpc = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800156 self.event_server = None
157 self.event_server_thread = None
158 self.event_client = None
159 self.connection_manager = None
Vic Yang4953fc12012-07-26 16:19:53 +0800160 self.charge_manager = None
Dean Liao88b93192014-10-23 19:37:41 +0800161 self._can_charge = True
Jon Salz8fa8e832012-07-13 19:04:09 +0800162 self.time_sanitizer = None
163 self.time_synced = False
Jon Salz0697cbf2012-07-04 15:14:04 +0800164 self.log_watcher = None
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800165 self.system_log_manager = None
Cheng-Yi Chiang835f2682013-05-06 22:15:48 +0800166 self.core_dump_manager = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800167 self.event_log = None
Vic Yange2c76a82014-10-30 12:48:19 -0700168 self.autotest_prespawner = None
169 self.pytest_prespawner = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800170 self.ui_process = None
Vic Yanga3cecf82014-12-26 00:44:21 -0800171 self._ui_initialized = False
Jon Salzc79a9982012-08-30 04:42:01 +0800172 self.dummy_shopfloor = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800173 self.invocations = {}
174 self.tests_to_run = deque()
175 self.visible_test = None
176 self.chrome = None
Jon Salz416f9cc2013-05-10 18:32:50 +0800177 self.hooks = None
Vic Yangd8990da2013-06-27 16:57:43 +0800178 self.cpu_usage_watcher = None
Hung-Te Lin23cb7612016-01-19 19:19:32 +0800179 self.thermal_watcher = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800180
181 self.options = None
182 self.args = None
183 self.test_list = None
Jon Salz128b0932013-07-03 16:55:26 +0800184 self.test_lists = None
Ricky Liang4bff3e32014-02-20 18:46:11 +0800185 self.run_id = None
186 self.scheduled_run_tests = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800187 self.env = None
Jon Salzb22d1172012-08-06 10:38:57 +0800188 self.last_idle = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800189 self.last_shutdown_time = None
cychiang21886742012-07-05 15:16:32 +0800190 self.last_update_check = None
Cheng-Yi Chiang194d3c02015-03-16 14:37:15 +0800191 self._suppress_periodic_update_messages = False
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +0800192 self._suppress_event_log_error_messages = False
Jon Salz8fa8e832012-07-13 19:04:09 +0800193 self.last_sync_time = None
Jon Salzb92c5112012-09-21 15:40:11 +0800194 self.last_log_disk_space_time = None
Jon Salz3c493bb2013-02-07 17:24:58 +0800195 self.last_log_disk_space_message = None
Justin Chuang83813982013-05-13 01:26:32 +0800196 self.last_check_battery_time = None
197 self.last_check_battery_message = None
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +0800198 self.last_kick_sync_time = None
Vic Yang311ddb82012-09-26 12:08:28 +0800199 self.exclusive_items = set()
Jon Salz0f996602012-10-03 15:26:48 +0800200 self.event_log = None
Dean Liao592e4d52013-01-10 20:06:39 +0800201 self.key_filter = None
Jon Salzce6a7f82013-06-10 18:22:54 +0800202 self.cpufreq_manager = None
Jon Salzd7550792013-07-12 05:49:27 +0800203 self.status = Status.UNINITIALIZED
Ricky Liang36512a32014-07-25 11:47:04 +0800204 self.ready_for_ui_connection = False
Peter Ammon1e1ec572014-06-26 17:56:32 -0700205 self.link_manager = None
Hung-Te Linef7f2be2015-07-20 20:38:51 +0800206 self.is_restart_requested = False
Jon Salz0697cbf2012-07-04 15:14:04 +0800207
Hung-Te Lin6a72c642015-12-13 22:09:09 +0800208 # TODO(hungte) Support controlling remote DUT.
209 self.dut = dut.Create()
210
Jon Salz85a39882012-07-05 16:45:04 +0800211 def test_or_root(event, parent_or_group=True):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800212 """Returns the test affected by a particular event.
Jon Salz85a39882012-07-05 16:45:04 +0800213
214 Args:
215 event: The event containing an optional 'path' attribute.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800216 parent_or_group: If True, returns the top-level parent for a test (the
Jon Salz85a39882012-07-05 16:45:04 +0800217 root node of the tests that need to be run together if the given test
218 path is to be run).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800219 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800220 try:
221 path = event.path
222 except AttributeError:
223 path = None
224
225 if path:
Jon Salz85a39882012-07-05 16:45:04 +0800226 test = self.test_list.lookup_path(path)
227 if parent_or_group:
228 test = test.get_top_level_parent_or_group()
229 return test
Jon Salz0697cbf2012-07-04 15:14:04 +0800230 else:
231 return self.test_list
232
233 self.event_handlers = {
Ricky Liang45c73e72015-01-15 15:00:30 +0800234 Event.Type.SWITCH_TEST: self.handle_switch_test,
235 Event.Type.SHOW_NEXT_ACTIVE_TEST:
236 lambda event: self.show_next_active_test(),
237 Event.Type.RESTART_TESTS:
238 lambda event: self.restart_tests(root=test_or_root(event)),
239 Event.Type.AUTO_RUN:
240 lambda event: self.auto_run(root=test_or_root(event)),
241 Event.Type.RE_RUN_FAILED:
242 lambda event: self.re_run_failed(root=test_or_root(event)),
243 Event.Type.RUN_TESTS_WITH_STATUS:
244 lambda event: self.run_tests_with_status(
245 event.status,
246 root=test_or_root(event)),
247 Event.Type.REVIEW:
248 lambda event: self.show_review_information(),
249 Event.Type.UPDATE_SYSTEM_INFO:
250 lambda event: self.update_system_info(),
251 Event.Type.STOP:
252 lambda event: self.stop(root=test_or_root(event, False),
253 fail=getattr(event, 'fail', False),
254 reason=getattr(event, 'reason', None)),
255 Event.Type.SET_VISIBLE_TEST:
256 lambda event: self.set_visible_test(
257 self.test_list.lookup_path(event.path)),
258 Event.Type.CLEAR_STATE:
259 lambda event: self.clear_state(
260 self.test_list.lookup_path(event.path)),
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800261 Event.Type.KEY_FILTER_MODE: self.handle_key_filter_mode,
Jon Salz0697cbf2012-07-04 15:14:04 +0800262 }
263
Jon Salz0697cbf2012-07-04 15:14:04 +0800264 self.web_socket_manager = None
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800265 self.terminal_manager = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800266
267 def destroy(self):
Ricky Liang74237a02014-09-18 15:11:23 +0800268 """Performs any shutdown tasks. Overrides base class method."""
Jon Salzd7550792013-07-12 05:49:27 +0800269 self.status = Status.TERMINATING
Jon Salz0697cbf2012-07-04 15:14:04 +0800270 if self.chrome:
271 self.chrome.kill()
272 self.chrome = None
Jon Salzc79a9982012-08-30 04:42:01 +0800273 if self.dummy_shopfloor:
274 self.dummy_shopfloor.kill()
275 self.dummy_shopfloor = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800276 if self.ui_process:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800277 process_utils.KillProcessTree(self.ui_process, 'ui')
Jon Salz0697cbf2012-07-04 15:14:04 +0800278 self.ui_process = None
279 if self.web_socket_manager:
280 logging.info('Stopping web sockets')
281 self.web_socket_manager.close()
282 self.web_socket_manager = None
283 if self.state_server_thread:
284 logging.info('Stopping state server')
285 self.state_server.shutdown()
286 self.state_server_thread.join()
287 self.state_server.server_close()
288 self.state_server_thread = None
289 if self.state_instance:
290 self.state_instance.close()
291 if self.event_server_thread:
292 logging.info('Stopping event server')
293 self.event_server.shutdown() # pylint: disable=E1101
294 self.event_server_thread.join()
295 self.event_server.server_close()
296 self.event_server_thread = None
297 if self.log_watcher:
298 if self.log_watcher.IsThreadStarted():
299 self.log_watcher.StopWatchThread()
300 self.log_watcher = None
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800301 if self.system_log_manager:
302 if self.system_log_manager.IsThreadRunning():
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +0800303 self.system_log_manager.Stop()
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +0800304 self.system_log_manager = None
Vic Yange2c76a82014-10-30 12:48:19 -0700305 if self.autotest_prespawner:
306 logging.info('Stopping autotest prespawner')
307 self.autotest_prespawner.stop()
308 self.autotest_prespawner = None
309 if self.pytest_prespawner:
310 logging.info('Stopping pytest prespawner')
311 self.pytest_prespawner.stop()
312 self.pytest_prespawner = None
Jon Salz0697cbf2012-07-04 15:14:04 +0800313 if self.event_client:
314 logging.info('Closing event client')
315 self.event_client.close()
316 self.event_client = None
Jon Salzddf0d052013-06-18 12:52:44 +0800317 if self.cpufreq_manager:
318 self.cpufreq_manager.Stop()
Jon Salz0697cbf2012-07-04 15:14:04 +0800319 if self.event_log:
320 self.event_log.Close()
321 self.event_log = None
Dean Liao592e4d52013-01-10 20:06:39 +0800322 if self.key_filter:
323 self.key_filter.Stop()
Vic Yangd8990da2013-06-27 16:57:43 +0800324 if self.cpu_usage_watcher:
325 self.cpu_usage_watcher.terminate()
Hung-Te Lin23cb7612016-01-19 19:19:32 +0800326 if self.thermal_watcher:
327 self.thermal_watcher.terminate()
Peter Ammon1e1ec572014-06-26 17:56:32 -0700328 if self.link_manager:
329 self.link_manager.Stop()
330 self.link_manager = None
Dean Liao592e4d52013-01-10 20:06:39 +0800331
Peter Ammon1e1ec572014-06-26 17:56:32 -0700332 super(Goofy, self).destroy()
Jon Salz0697cbf2012-07-04 15:14:04 +0800333 logging.info('Done destroying Goofy')
Jon Salzd7550792013-07-12 05:49:27 +0800334 self.status = Status.TERMINATED
Jon Salz0697cbf2012-07-04 15:14:04 +0800335
336 def start_state_server(self):
Jon Salz2af235d2013-06-24 14:47:21 +0800337 # Before starting state server, remount stateful partitions with
338 # no commit flag. The default commit time (commit=600) makes corruption
339 # too likely.
Hung-Te Lin1968d9c2016-01-08 22:55:46 +0800340 sys_utils.ResetCommitTime()
Jon Salz2af235d2013-06-24 14:47:21 +0800341
Jon Salz0697cbf2012-07-04 15:14:04 +0800342 self.state_instance, self.state_server = (
Ricky Liang45c73e72015-01-15 15:00:30 +0800343 state.create_server(bind_address='0.0.0.0'))
Jon Salz16d10542012-07-23 12:18:45 +0800344 self.goofy_rpc = GoofyRPC(self)
345 self.goofy_rpc.RegisterMethods(self.state_instance)
Jon Salz0697cbf2012-07-04 15:14:04 +0800346 logging.info('Starting state server')
347 self.state_server_thread = threading.Thread(
Ricky Liang45c73e72015-01-15 15:00:30 +0800348 target=self.state_server.serve_forever,
349 name='StateServer')
Jon Salz0697cbf2012-07-04 15:14:04 +0800350 self.state_server_thread.start()
351
352 def start_event_server(self):
353 self.event_server = EventServer()
354 logging.info('Starting factory event server')
355 self.event_server_thread = threading.Thread(
Ricky Liang45c73e72015-01-15 15:00:30 +0800356 target=self.event_server.serve_forever,
357 name='EventServer') # pylint: disable=E1101
Jon Salz0697cbf2012-07-04 15:14:04 +0800358 self.event_server_thread.start()
359
360 self.event_client = EventClient(
Ricky Liang45c73e72015-01-15 15:00:30 +0800361 callback=self.handle_event, event_loop=self.run_queue)
Jon Salz0697cbf2012-07-04 15:14:04 +0800362
363 self.web_socket_manager = WebSocketManager(self.uuid)
Ricky Liang45c73e72015-01-15 15:00:30 +0800364 self.state_server.add_handler('/event',
365 self.web_socket_manager.handle_web_socket)
Jon Salz0697cbf2012-07-04 15:14:04 +0800366
Wei-Ning Huang38b75f02015-02-25 18:25:14 +0800367 def start_terminal_server(self):
368 self.terminal_manager = TerminalManager()
369 self.state_server.add_handler('/pty',
370 self.terminal_manager.handle_web_socket)
371
Jon Salz0697cbf2012-07-04 15:14:04 +0800372 def start_ui(self):
373 ui_proc_args = [
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +0800374 os.path.join(paths.FACTORY_PACKAGE_PATH, 'test', 'ui.py'),
Ricky Liang45c73e72015-01-15 15:00:30 +0800375 self.options.test_list
376 ]
Jon Salz0697cbf2012-07-04 15:14:04 +0800377 if self.options.verbose:
378 ui_proc_args.append('-v')
379 logging.info('Starting ui %s', ui_proc_args)
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800380 self.ui_process = process_utils.Spawn(ui_proc_args)
Jon Salz0697cbf2012-07-04 15:14:04 +0800381 logging.info('Waiting for UI to come up...')
382 self.event_client.wait(
Ricky Liang45c73e72015-01-15 15:00:30 +0800383 lambda event: event.type == Event.Type.UI_READY)
Jon Salz0697cbf2012-07-04 15:14:04 +0800384 logging.info('UI has started')
385
386 def set_visible_test(self, test):
387 if self.visible_test == test:
388 return
Jon Salz2f2d42c2012-07-30 12:30:34 +0800389 if test and not test.has_ui:
390 return
Jon Salz0697cbf2012-07-04 15:14:04 +0800391
392 if test:
393 test.update_state(visible=True)
394 if self.visible_test:
395 self.visible_test.update_state(visible=False)
396 self.visible_test = test
397
Ricky Liang48e47f92014-02-26 19:31:51 +0800398 def log_startup_messages(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800399 """Logs the tail of var/log/messages and mosys and EC console logs."""
Jon Salzd4306c82012-11-30 15:16:36 +0800400 # TODO(jsalz): This is mostly a copy-and-paste of code in init_states,
401 # for factory-3004.B only. Consolidate and merge back to ToT.
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800402 if sys_utils.InChroot():
Jon Salzd4306c82012-11-30 15:16:36 +0800403 return
404
405 try:
Hung-Te Lin1a4e30c2016-01-08 23:25:10 +0800406 var_log_messages = sys_utils.GetVarLogMessagesBeforeReboot()
Jon Salzd4306c82012-11-30 15:16:36 +0800407 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +0800408 'Tail of /var/log/messages before last reboot:\n'
409 '%s', ('\n'.join(
410 ' ' + x for x in var_log_messages)))
Jon Salzd4306c82012-11-30 15:16:36 +0800411 except: # pylint: disable=W0702
412 logging.exception('Unable to grok /var/log/messages')
413
414 try:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800415 mosys_log = process_utils.Spawn(
Jon Salzd4306c82012-11-30 15:16:36 +0800416 ['mosys', 'eventlog', 'list'],
417 read_stdout=True, log_stderr_on_error=True).stdout_data
418 logging.info('System eventlog from mosys:\n%s\n', mosys_log)
419 except: # pylint: disable=W0702
420 logging.exception('Unable to read mosys eventlog')
421
Dean Liao88b93192014-10-23 19:37:41 +0800422 self.log_ec_console()
423 self.log_ec_panic_info()
424
425 @staticmethod
426 def log_ec_console():
427 """Logs EC console log into logging.info.
428
429 It logs an error message in logging.exception if an exception is raised
430 when getting EC console log.
431 For unsupported device, it logs unsupport message in logging.info
432
433 Returns:
434 EC console log string.
435 """
Jon Salzd4306c82012-11-30 15:16:36 +0800436 try:
Hung-Te Linb3a09642015-12-14 18:57:23 +0800437 ec_console_log = dut.Create().ec.GetECConsoleLog()
Jon Salzd4306c82012-11-30 15:16:36 +0800438 logging.info('EC console log after reboot:\n%s\n', ec_console_log)
Dean Liao88b93192014-10-23 19:37:41 +0800439 return ec_console_log
440 except NotImplementedError:
441 logging.info('EC console log not supported')
Jon Salzd4306c82012-11-30 15:16:36 +0800442 except: # pylint: disable=W0702
443 logging.exception('Error retrieving EC console log')
444
Dean Liao88b93192014-10-23 19:37:41 +0800445 @staticmethod
446 def log_ec_panic_info():
447 """Logs EC panic info into logging.info.
448
449 It logs an error message in logging.exception if an exception is raised
450 when getting EC panic info.
451 For unsupported device, it logs unsupport message in logging.info
452
453 Returns:
454 EC panic info string.
455 """
Vic Yang079f9872013-07-01 11:32:00 +0800456 try:
Hung-Te Linb3a09642015-12-14 18:57:23 +0800457 ec_panic_info = dut.Create().ec.GetECPanicInfo()
Vic Yang079f9872013-07-01 11:32:00 +0800458 logging.info('EC panic info after reboot:\n%s\n', ec_panic_info)
Dean Liao88b93192014-10-23 19:37:41 +0800459 return ec_panic_info
460 except NotImplementedError:
461 logging.info('EC panic info is not supported')
Vic Yang079f9872013-07-01 11:32:00 +0800462 except: # pylint: disable=W0702
463 logging.exception('Error retrieving EC panic info')
464
Ricky Liang48e47f92014-02-26 19:31:51 +0800465 def shutdown(self, operation):
466 """Starts shutdown procedure.
467
468 Args:
Vic (Chun-Ju) Yang05b0d952014-04-28 17:39:09 +0800469 operation: The shutdown operation (reboot, full_reboot, or halt).
Ricky Liang48e47f92014-02-26 19:31:51 +0800470 """
471 active_tests = []
472 for test in self.test_list.walk():
473 if not test.is_leaf():
474 continue
475
476 test_state = test.get_state()
477 if test_state.status == TestState.ACTIVE:
478 active_tests.append(test)
479
Ricky Liang48e47f92014-02-26 19:31:51 +0800480 if not (len(active_tests) == 1 and
481 isinstance(active_tests[0], factory.ShutdownStep)):
482 logging.error(
483 'Calling Goofy shutdown outside of the shutdown factory test')
484 return
485
486 logging.info('Start Goofy shutdown (%s)', operation)
487 # Save pending test list in the state server
488 self.state_instance.set_shared_data(
489 'tests_after_shutdown',
490 [t.path for t in self.tests_to_run])
491 # Save shutdown time
492 self.state_instance.set_shared_data('shutdown_time', time.time())
493
494 with self.env.lock:
495 self.event_log.Log('shutdown', operation=operation)
496 shutdown_result = self.env.shutdown(operation)
497 if shutdown_result:
498 # That's all, folks!
Peter Ammon1e1ec572014-06-26 17:56:32 -0700499 self.run_enqueue(None)
Ricky Liang48e47f92014-02-26 19:31:51 +0800500 else:
501 # Just pass (e.g., in the chroot).
502 self.state_instance.set_shared_data('tests_after_shutdown', None)
503 # Send event with no fields to indicate that there is no
504 # longer a pending shutdown.
505 self.event_client.post_event(Event(Event.Type.PENDING_SHUTDOWN))
506
507 def handle_shutdown_complete(self, test):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800508 """Handles the case where a shutdown was detected during a shutdown step.
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800509
Ricky Liang6fe218c2013-12-27 15:17:17 +0800510 Args:
511 test: The ShutdownStep.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800512 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800513 test_state = test.update_state(increment_shutdown_count=1)
514 logging.info('Detected shutdown (%d of %d)',
Ricky Liang48e47f92014-02-26 19:31:51 +0800515 test_state.shutdown_count, test.iterations)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800516
Ricky Liang48e47f92014-02-26 19:31:51 +0800517 # Insert current shutdown test at the front of the list of tests to run
518 # after shutdown. This is to continue on post-shutdown verification in the
519 # shutdown step.
520 tests_after_shutdown = self.state_instance.get_shared_data(
521 'tests_after_shutdown', optional=True)
522 if not tests_after_shutdown:
523 self.state_instance.set_shared_data('tests_after_shutdown', [test.path])
524 elif isinstance(tests_after_shutdown, list):
525 self.state_instance.set_shared_data(
526 'tests_after_shutdown', [test.path] + tests_after_shutdown)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800527
Ricky Liang48e47f92014-02-26 19:31:51 +0800528 # Set 'post_shutdown' to inform shutdown test that a shutdown just occurred.
Ricky Liangb7eb8772014-09-15 18:05:22 +0800529 self.state_instance.set_shared_data(
530 state.POST_SHUTDOWN_TAG % test.path,
531 self.state_instance.get_test_state(test.path).invocation)
Jon Salz258a40c2012-04-19 12:34:01 +0800532
Jon Salz0697cbf2012-07-04 15:14:04 +0800533 def init_states(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800534 """Initializes all states on startup."""
Jon Salz0697cbf2012-07-04 15:14:04 +0800535 for test in self.test_list.get_all_tests():
536 # Make sure the state server knows about all the tests,
537 # defaulting to an untested state.
538 test.update_state(update_parent=False, visible=False)
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800539
Jon Salz0697cbf2012-07-04 15:14:04 +0800540 var_log_messages = None
Vic Yanga9c32212012-08-16 20:07:54 +0800541 mosys_log = None
Vic Yange4c275d2012-08-28 01:50:20 +0800542 ec_console_log = None
Vic Yang079f9872013-07-01 11:32:00 +0800543 ec_panic_info = None
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800544
Jon Salz0697cbf2012-07-04 15:14:04 +0800545 # Any 'active' tests should be marked as failed now.
546 for test in self.test_list.walk():
Jon Salza6711d72012-07-18 14:33:03 +0800547 if not test.is_leaf():
548 # Don't bother with parents; they will be updated when their
549 # children are updated.
550 continue
551
Jon Salz0697cbf2012-07-04 15:14:04 +0800552 test_state = test.get_state()
553 if test_state.status != TestState.ACTIVE:
554 continue
555 if isinstance(test, factory.ShutdownStep):
556 # Shutdown while the test was active - that's good.
Ricky Liang48e47f92014-02-26 19:31:51 +0800557 self.handle_shutdown_complete(test)
Jon Salz0697cbf2012-07-04 15:14:04 +0800558 else:
559 # Unexpected shutdown. Grab /var/log/messages for context.
560 if var_log_messages is None:
561 try:
562 var_log_messages = (
Hung-Te Lin1a4e30c2016-01-08 23:25:10 +0800563 sys_utils.GetVarLogMessagesBeforeReboot())
Jon Salz0697cbf2012-07-04 15:14:04 +0800564 # Write it to the log, to make it easier to
565 # correlate with /var/log/messages.
566 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +0800567 'Unexpected shutdown. '
568 'Tail of /var/log/messages before last reboot:\n'
569 '%s', ('\n'.join(
570 ' ' + x for x in var_log_messages)))
Jon Salz0697cbf2012-07-04 15:14:04 +0800571 except: # pylint: disable=W0702
572 logging.exception('Unable to grok /var/log/messages')
573 var_log_messages = []
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800574
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800575 if mosys_log is None and not sys_utils.InChroot():
Jon Salz008f4ea2012-08-28 05:39:45 +0800576 try:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +0800577 mosys_log = process_utils.Spawn(
Jon Salz008f4ea2012-08-28 05:39:45 +0800578 ['mosys', 'eventlog', 'list'],
579 read_stdout=True, log_stderr_on_error=True).stdout_data
580 # Write it to the log also.
581 logging.info('System eventlog from mosys:\n%s\n', mosys_log)
582 except: # pylint: disable=W0702
583 logging.exception('Unable to read mosys eventlog')
Vic Yanga9c32212012-08-16 20:07:54 +0800584
Vic Yange4c275d2012-08-28 01:50:20 +0800585 if ec_console_log is None:
Dean Liao88b93192014-10-23 19:37:41 +0800586 ec_console_log = self.log_ec_console()
Vic Yange4c275d2012-08-28 01:50:20 +0800587
Vic Yang079f9872013-07-01 11:32:00 +0800588 if ec_panic_info is None:
Dean Liao88b93192014-10-23 19:37:41 +0800589 ec_panic_info = self.log_ec_panic_info()
Vic Yang079f9872013-07-01 11:32:00 +0800590
Jon Salz0697cbf2012-07-04 15:14:04 +0800591 error_msg = 'Unexpected shutdown while test was running'
592 self.event_log.Log('end_test',
Ricky Liang45c73e72015-01-15 15:00:30 +0800593 path=test.path,
594 status=TestState.FAILED,
595 invocation=test.get_state().invocation,
596 error_msg=error_msg,
597 var_log_messages='\n'.join(var_log_messages),
598 mosys_log=mosys_log)
Jon Salz0697cbf2012-07-04 15:14:04 +0800599 test.update_state(
Ricky Liang45c73e72015-01-15 15:00:30 +0800600 status=TestState.FAILED,
601 error_msg=error_msg)
Chun-Ta Lin87c2dac2015-05-02 01:35:01 -0700602 # Trigger the OnTestFailure callback.
Claire Changd1961a22015-08-05 16:15:55 +0800603 self.run_queue.put(lambda: self.test_fail(test))
Hung-Te Linf2f78f72012-02-08 19:27:11 +0800604
Jon Salz50efe942012-07-26 11:54:10 +0800605 if not test.never_fails:
606 # For "never_fails" tests (such as "Start"), don't cancel
607 # pending tests, since reboot is expected.
608 factory.console.info('Unexpected shutdown while test %s '
609 'running; cancelling any pending tests',
610 test.path)
611 self.state_instance.set_shared_data('tests_after_shutdown', [])
Jon Salz69806bb2012-07-20 18:05:02 +0800612
Jon Salz008f4ea2012-08-28 05:39:45 +0800613 self.update_skipped_tests()
614
615 def update_skipped_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800616 """Updates skipped states based on run_if."""
Jon Salz885dcac2013-07-23 16:39:50 +0800617 env = TestArgEnv()
Ricky Liang45c73e72015-01-15 15:00:30 +0800618
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800619 def _evaluate_skip_from_run_if(test):
620 """Returns the run_if evaluation of the test.
621
622 Args:
623 test: A FactoryTest object.
624
625 Returns:
626 The run_if evaluation result. Returns False if the test has no
627 run_if argument.
628 """
629 value = None
630 if test.run_if_expr:
631 try:
632 value = test.run_if_expr(env)
633 except: # pylint: disable=W0702
634 logging.exception('Unable to evaluate run_if expression for %s',
635 test.path)
636 # But keep going; we have no choice. This will end up
637 # always activating the test.
638 elif test.run_if_table_name:
639 try:
640 aux = shopfloor.get_selected_aux_data(test.run_if_table_name)
641 value = aux.get(test.run_if_col)
642 except ValueError:
643 # Not available; assume it shouldn't be skipped
644 pass
645
646 if value is None:
647 skip = False
648 else:
649 skip = (not value) ^ t.run_if_not
650 return skip
651
652 # Gets all run_if evaluation, and stores results in skip_map.
653 skip_map = dict()
Jon Salz008f4ea2012-08-28 05:39:45 +0800654 for t in self.test_list.walk():
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800655 skip_map[t.path] = _evaluate_skip_from_run_if(t)
Jon Salz885dcac2013-07-23 16:39:50 +0800656
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800657 # Propagates the skip value from root of tree and updates skip_map.
658 def _update_skip_map_from_node(test, skip_from_parent):
659 """Updates skip_map from a given node.
Jon Salz885dcac2013-07-23 16:39:50 +0800660
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800661 Given a FactoryTest node and the skip value from parent, updates the
662 skip value of current node in the skip_map if skip value from parent is
663 True. If this node has children, recursively propagate this value to all
664 its children, that is, all its subtests.
665 Note that this function only updates value in skip_map, not the actual
666 test_list tree.
Jon Salz008f4ea2012-08-28 05:39:45 +0800667
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800668 Args:
669 test: The given FactoryTest object. It is a node in the test_list tree.
670 skip_from_parent: The skip value which propagates from the parent of
671 input node.
672 """
673 skip_this_tree = skip_from_parent or skip_map[test.path]
674 if skip_this_tree:
675 logging.info('Skip from node %r', test.path)
676 skip_map[test.path] = True
677 if test.is_leaf():
678 return
679 # Propagates skip value to its subtests
680 for subtest in test.subtests:
681 _update_skip_map_from_node(subtest, skip_this_tree)
682
683 _update_skip_map_from_node(self.test_list, False)
684
685 # Updates the skip value from skip_map to test_list tree. Also, updates test
686 # status if needed.
687 for t in self.test_list.walk():
688 skip = skip_map[t.path]
689 test_state = t.get_state()
690 if ((not skip) and
691 (test_state.status == TestState.PASSED) and
692 (test_state.error_msg == TestState.SKIPPED_MSG)):
693 # It was marked as skipped before, but now we need to run it.
694 # Mark as untested.
695 t.update_state(skip=skip, status=TestState.UNTESTED, error_msg='')
696 else:
697 t.update_state(skip=skip)
Jon Salz008f4ea2012-08-28 05:39:45 +0800698
Jon Salz0697cbf2012-07-04 15:14:04 +0800699 def show_next_active_test(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800700 """Rotates to the next visible active test."""
Jon Salz0697cbf2012-07-04 15:14:04 +0800701 self.reap_completed_tests()
702 active_tests = [
Ricky Liang45c73e72015-01-15 15:00:30 +0800703 t for t in self.test_list.walk()
704 if t.is_leaf() and t.get_state().status == TestState.ACTIVE]
Jon Salz0697cbf2012-07-04 15:14:04 +0800705 if not active_tests:
706 return
Jon Salz4f6c7172012-06-11 20:45:36 +0800707
Jon Salz0697cbf2012-07-04 15:14:04 +0800708 try:
709 next_test = active_tests[
Ricky Liang45c73e72015-01-15 15:00:30 +0800710 (active_tests.index(self.visible_test) + 1) % len(active_tests)]
Jon Salz0697cbf2012-07-04 15:14:04 +0800711 except ValueError: # visible_test not present in active_tests
712 next_test = active_tests[0]
Jon Salz4f6c7172012-06-11 20:45:36 +0800713
Jon Salz0697cbf2012-07-04 15:14:04 +0800714 self.set_visible_test(next_test)
Jon Salz4f6c7172012-06-11 20:45:36 +0800715
Jon Salz0697cbf2012-07-04 15:14:04 +0800716 def handle_event(self, event):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800717 """Handles an event from the event server."""
Jon Salz0697cbf2012-07-04 15:14:04 +0800718 handler = self.event_handlers.get(event.type)
719 if handler:
720 handler(event)
721 else:
722 # We don't register handlers for all event types - just ignore
723 # this event.
724 logging.debug('Unbound event type %s', event.type)
Jon Salz4f6c7172012-06-11 20:45:36 +0800725
Vic Yangaabf9fd2013-04-09 18:56:13 +0800726 def check_critical_factory_note(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800727 """Returns True if the last factory note is critical."""
Vic Yangaabf9fd2013-04-09 18:56:13 +0800728 notes = self.state_instance.get_shared_data('factory_note', True)
729 return notes and notes[-1]['level'] == 'CRITICAL'
730
Hung-Te Linef7f2be2015-07-20 20:38:51 +0800731 def schedule_restart(self):
732 """Schedules a restart event when any invocation is completed."""
733 self.is_restart_requested = True
734
735 def invocation_completion(self):
736 """Callback when an invocation is completed."""
737 if self.is_restart_requested:
738 logging.info('Restart by scheduled event.')
739 self.is_restart_requested = False
740 self.restart_tests()
741 else:
742 self.run_next_test()
743
Jon Salz0697cbf2012-07-04 15:14:04 +0800744 def run_next_test(self):
henryhsu4cc6b022014-04-22 17:12:42 +0800745 """Runs the next eligible test (or tests) in self.tests_to_run.
746
747 We have three kinds of the next eligible test:
748 1. normal
749 2. backgroundable
750 3. force_background
751
752 And we have four situations of the ongoing invocations:
753 a. only a running normal test
754 b. all running tests are backgroundable
755 c. all running tests are force_background
756 d. all running tests are any combination of backgroundable and
757 force_background
758
759 When a test would like to be run, it must follow the rules:
760 [1] cannot run with [abd]
761 [2] cannot run with [a]
762 All the other combinations are allowed
763 """
Jon Salz0697cbf2012-07-04 15:14:04 +0800764 self.reap_completed_tests()
Vic Yangaabf9fd2013-04-09 18:56:13 +0800765 if self.tests_to_run and self.check_critical_factory_note():
766 self.tests_to_run.clear()
767 return
Jon Salz0697cbf2012-07-04 15:14:04 +0800768 while self.tests_to_run:
Ricky Liang6fe218c2013-12-27 15:17:17 +0800769 logging.debug('Tests to run: %s', [x.path for x in self.tests_to_run])
Jon Salz94eb56f2012-06-12 18:01:12 +0800770
Jon Salz0697cbf2012-07-04 15:14:04 +0800771 test = self.tests_to_run[0]
Jon Salz94eb56f2012-06-12 18:01:12 +0800772
Jon Salz0697cbf2012-07-04 15:14:04 +0800773 if test in self.invocations:
774 logging.info('Next test %s is already running', test.path)
775 self.tests_to_run.popleft()
776 return
Jon Salz94eb56f2012-06-12 18:01:12 +0800777
Jon Salza1412922012-07-23 16:04:17 +0800778 for requirement in test.require_run:
779 for i in requirement.test.walk():
780 if i.get_state().status == TestState.ACTIVE:
Jon Salz304a75d2012-07-06 11:14:15 +0800781 logging.info('Waiting for active test %s to complete '
Jon Salza1412922012-07-23 16:04:17 +0800782 'before running %s', i.path, test.path)
Jon Salz304a75d2012-07-06 11:14:15 +0800783 return
784
henryhsu4cc6b022014-04-22 17:12:42 +0800785 def is_normal_test(test):
786 return not (test.backgroundable or test.force_background)
787
788 # [1] cannot run with [abd].
789 if self.invocations and is_normal_test(test) and any(
790 [not x.force_background for x in self.invocations]):
791 logging.info('Waiting for non-force_background tests to '
792 'complete before running %s', test.path)
793 return
794
795 # [2] cannot run with [a].
796 if self.invocations and test.backgroundable and any(
797 [is_normal_test(x) for x in self.invocations]):
798 logging.info('Waiting for normal tests to '
799 'complete before running %s', test.path)
Jon Salz0697cbf2012-07-04 15:14:04 +0800800 return
Jon Salz94eb56f2012-06-12 18:01:12 +0800801
Jon Salz3e6f5202012-10-15 15:08:29 +0800802 if test.get_state().skip:
803 factory.console.info('Skipping test %s', test.path)
804 test.update_state(status=TestState.PASSED,
805 error_msg=TestState.SKIPPED_MSG)
806 self.tests_to_run.popleft()
807 continue
808
Jon Salz0697cbf2012-07-04 15:14:04 +0800809 self.tests_to_run.popleft()
Jon Salz94eb56f2012-06-12 18:01:12 +0800810
Jon Salz304a75d2012-07-06 11:14:15 +0800811 untested = set()
Jon Salza1412922012-07-23 16:04:17 +0800812 for requirement in test.require_run:
813 for i in requirement.test.walk():
814 if i == test:
Jon Salz304a75d2012-07-06 11:14:15 +0800815 # We've hit this test itself; stop checking
816 break
Jon Salza1412922012-07-23 16:04:17 +0800817 if ((i.get_state().status == TestState.UNTESTED) or
818 (requirement.passed and i.get_state().status !=
819 TestState.PASSED)):
Jon Salz304a75d2012-07-06 11:14:15 +0800820 # Found an untested test; move on to the next
821 # element in require_run.
Jon Salza1412922012-07-23 16:04:17 +0800822 untested.add(i)
Jon Salz304a75d2012-07-06 11:14:15 +0800823 break
824
825 if untested:
826 untested_paths = ', '.join(sorted([x.path for x in untested]))
827 if self.state_instance.get_shared_data('engineering_mode',
828 optional=True):
829 # In engineering mode, we'll let it go.
830 factory.console.warn('In engineering mode; running '
831 '%s even though required tests '
832 '[%s] have not completed',
833 test.path, untested_paths)
834 else:
835 # Not in engineering mode; mark it failed.
836 error_msg = ('Required tests [%s] have not been run yet'
837 % untested_paths)
838 factory.console.error('Not running %s: %s',
839 test.path, error_msg)
840 test.update_state(status=TestState.FAILED,
841 error_msg=error_msg)
842 continue
843
Ricky Liang48e47f92014-02-26 19:31:51 +0800844 if (isinstance(test, factory.ShutdownStep) and
Ricky Liangb7eb8772014-09-15 18:05:22 +0800845 self.state_instance.get_shared_data(
846 state.POST_SHUTDOWN_TAG % test.path, optional=True)):
Ricky Liang48e47f92014-02-26 19:31:51 +0800847 # Invoking post shutdown method of shutdown test. We should retain the
848 # iterations_left and retries_left of the original test state.
849 test_state = self.state_instance.get_test_state(test.path)
850 self._run_test(test, test_state.iterations_left,
851 test_state.retries_left)
852 else:
853 # Starts a new test run; reset iterations and retries.
854 self._run_test(test, test.iterations, test.retries)
Jon Salz1acc8742012-07-17 17:45:55 +0800855
Cheng-Yi Chiangce05c002013-04-04 02:13:17 +0800856 def _run_test(self, test, iterations_left=None, retries_left=None):
Vic Yanga3cecf82014-12-26 00:44:21 -0800857 if not self._ui_initialized and not test.is_no_host():
858 self.init_ui()
Vic Yang08505c72015-01-06 17:01:53 -0800859 invoc = TestInvocation(
Hung-Te Linef7f2be2015-07-20 20:38:51 +0800860 self, test, on_completion=self.invocation_completion,
Claire Changd1961a22015-08-05 16:15:55 +0800861 on_test_failure=lambda: self.test_fail(test))
Jon Salz1acc8742012-07-17 17:45:55 +0800862 new_state = test.update_state(
Ricky Liang48e47f92014-02-26 19:31:51 +0800863 status=TestState.ACTIVE, increment_count=1, error_msg='',
864 invocation=invoc.uuid, iterations_left=iterations_left,
865 retries_left=retries_left,
866 visible=(self.visible_test == test))
Jon Salz1acc8742012-07-17 17:45:55 +0800867 invoc.count = new_state.count
868
869 self.invocations[test] = invoc
870 if self.visible_test is None and test.has_ui:
871 self.set_visible_test(test)
Vic Yang311ddb82012-09-26 12:08:28 +0800872 self.check_exclusive()
Jon Salz1acc8742012-07-17 17:45:55 +0800873 invoc.start()
Jon Salz5f2a0672012-05-22 17:14:06 +0800874
Vic Yang311ddb82012-09-26 12:08:28 +0800875 def check_exclusive(self):
Jon Salzce6a7f82013-06-10 18:22:54 +0800876 # alias since this is really long
877 EXCL_OPT = factory.FactoryTest.EXCLUSIVE_OPTIONS
878
Vic Yang311ddb82012-09-26 12:08:28 +0800879 current_exclusive_items = set([
Jon Salzce6a7f82013-06-10 18:22:54 +0800880 item for item in EXCL_OPT
Vic Yang311ddb82012-09-26 12:08:28 +0800881 if any([test.is_exclusive(item) for test in self.invocations])])
882
883 new_exclusive_items = current_exclusive_items - self.exclusive_items
Jon Salzce6a7f82013-06-10 18:22:54 +0800884 if EXCL_OPT.NETWORKING in new_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800885 logging.info('Disabling network')
886 self.connection_manager.DisableNetworking()
Jon Salzce6a7f82013-06-10 18:22:54 +0800887 if EXCL_OPT.CHARGER in new_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800888 logging.info('Stop controlling charger')
889
890 new_non_exclusive_items = self.exclusive_items - current_exclusive_items
Jon Salzce6a7f82013-06-10 18:22:54 +0800891 if EXCL_OPT.NETWORKING in new_non_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800892 logging.info('Re-enabling network')
893 self.connection_manager.EnableNetworking()
Jon Salzce6a7f82013-06-10 18:22:54 +0800894 if EXCL_OPT.CHARGER in new_non_exclusive_items:
Vic Yang311ddb82012-09-26 12:08:28 +0800895 logging.info('Start controlling charger')
896
Jon Salzce6a7f82013-06-10 18:22:54 +0800897 if self.cpufreq_manager:
898 enabled = EXCL_OPT.CPUFREQ not in current_exclusive_items
899 try:
900 self.cpufreq_manager.SetEnabled(enabled)
901 except: # pylint: disable=W0702
902 logging.exception('Unable to %s cpufreq services',
903 'enable' if enabled else 'disable')
904
Ricky Liang0f9978e2015-01-30 08:19:17 +0000905 # Only adjust charge state if not excluded
906 if (EXCL_OPT.CHARGER not in current_exclusive_items and
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800907 not sys_utils.InChroot()):
Ricky Liang0f9978e2015-01-30 08:19:17 +0000908 if self.charge_manager:
Cheng-Yi Chiangd8186952013-04-04 23:41:14 +0800909 self.charge_manager.AdjustChargeState()
910 else:
Dean Liao88b93192014-10-23 19:37:41 +0800911 self.charge()
Vic Yang311ddb82012-09-26 12:08:28 +0800912
913 self.exclusive_items = current_exclusive_items
Jon Salz5da61e62012-05-31 13:06:22 +0800914
Dean Liao88b93192014-10-23 19:37:41 +0800915 def charge(self):
916 """Charges the board.
917
918 It won't try again if last time SetChargeState raised an exception.
919 """
920 if not self._can_charge:
921 return
922
923 try:
Ricky Liang9ac35e02015-01-30 16:01:32 +0800924 if self.charge_manager:
925 self.charge_manager.StartCharging()
926 else:
Hung-Te Lin6a72c642015-12-13 22:09:09 +0800927 self.dut.power.SetChargeState(self.dut.power.ChargeState.CHARGE)
Dean Liao88b93192014-10-23 19:37:41 +0800928 except NotImplementedError:
929 logging.info('Charging is not supported')
930 self._can_charge = False
Hung-Te Lin6a72c642015-12-13 22:09:09 +0800931 except dut.DUTException:
Dean Liao88b93192014-10-23 19:37:41 +0800932 logging.exception('Unable to set charge state on this board')
933 self._can_charge = False
934
cychiang21886742012-07-05 15:16:32 +0800935 def check_for_updates(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800936 """Schedules an asynchronous check for updates if necessary."""
cychiang21886742012-07-05 15:16:32 +0800937 if not self.test_list.options.update_period_secs:
938 # Not enabled.
939 return
940
941 now = time.time()
942 if self.last_update_check and (
943 now - self.last_update_check <
944 self.test_list.options.update_period_secs):
945 # Not yet time for another check.
946 return
947
948 self.last_update_check = now
949
950 def handle_check_for_update(reached_shopfloor, md5sum, needs_update):
951 if reached_shopfloor:
952 new_update_md5sum = md5sum if needs_update else None
Hung-Te Line594e5d2015-12-16 02:36:05 +0800953 if self.dut.info.update_md5sum != new_update_md5sum:
cychiang21886742012-07-05 15:16:32 +0800954 logging.info('Received new update MD5SUM: %s', new_update_md5sum)
Hung-Te Line594e5d2015-12-16 02:36:05 +0800955 self.dut.info.Overrides('update_md5sum', new_update_md5sum)
Peter Ammon1e1ec572014-06-26 17:56:32 -0700956 self.run_enqueue(self.update_system_info)
Cheng-Yi Chiang194d3c02015-03-16 14:37:15 +0800957 else:
958 if not self._suppress_periodic_update_messages:
959 logging.warning('Suppress error messages for periodic update checking'
960 ' after the first one.')
961 self._suppress_periodic_update_messages = True
cychiang21886742012-07-05 15:16:32 +0800962
963 updater.CheckForUpdateAsync(
Ricky Liang45c73e72015-01-15 15:00:30 +0800964 handle_check_for_update,
Cheng-Yi Chiang194d3c02015-03-16 14:37:15 +0800965 self.test_list.options.shopfloor_timeout_secs,
966 self._suppress_periodic_update_messages)
cychiang21886742012-07-05 15:16:32 +0800967
Jon Salza6711d72012-07-18 14:33:03 +0800968 def cancel_pending_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800969 """Cancels any tests in the run queue."""
Jon Salza6711d72012-07-18 14:33:03 +0800970 self.run_tests([])
971
Ricky Liang4bff3e32014-02-20 18:46:11 +0800972 def restore_active_run_state(self):
973 """Restores active run id and the list of scheduled tests."""
974 self.run_id = self.state_instance.get_shared_data('run_id', optional=True)
975 self.scheduled_run_tests = self.state_instance.get_shared_data(
976 'scheduled_run_tests', optional=True)
977
978 def set_active_run_state(self):
979 """Sets active run id and the list of scheduled tests."""
980 self.run_id = str(uuid.uuid4())
981 self.scheduled_run_tests = [test.path for test in self.tests_to_run]
982 self.state_instance.set_shared_data('run_id', self.run_id)
983 self.state_instance.set_shared_data('scheduled_run_tests',
984 self.scheduled_run_tests)
985
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +0800986 def run_tests(self, subtrees, status_filter=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800987 """Runs tests under subtree.
Jon Salz258a40c2012-04-19 12:34:01 +0800988
Jon Salz0697cbf2012-07-04 15:14:04 +0800989 The tests are run in order unless one fails (then stops).
990 Backgroundable tests are run simultaneously; when a foreground test is
991 encountered, we wait for all active tests to finish before continuing.
Jon Salzb1b39092012-05-03 02:05:09 +0800992
Ricky Liang6fe218c2013-12-27 15:17:17 +0800993 Args:
994 subtrees: Node or nodes containing tests to run (may either be
995 a single test or a list). Duplicates will be ignored.
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +0800996 status_filter: List of available test states. Only run the tests which
997 states are in the list. Set to None if all test states are available.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +0800998 """
Hung-Te Lin410f70a2015-12-15 14:53:42 +0800999 self.dut.hooks.OnTestStart()
Vic Yang08505c72015-01-06 17:01:53 -08001000
Jon Salz0697cbf2012-07-04 15:14:04 +08001001 if type(subtrees) != list:
1002 subtrees = [subtrees]
Jon Salz258a40c2012-04-19 12:34:01 +08001003
Jon Salz0697cbf2012-07-04 15:14:04 +08001004 # Nodes we've seen so far, to avoid duplicates.
1005 seen = set()
Jon Salz94eb56f2012-06-12 18:01:12 +08001006
Jon Salz0697cbf2012-07-04 15:14:04 +08001007 self.tests_to_run = deque()
1008 for subtree in subtrees:
1009 for test in subtree.walk():
1010 if test in seen:
1011 continue
1012 seen.add(test)
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001013
Jon Salz0697cbf2012-07-04 15:14:04 +08001014 if not test.is_leaf():
1015 continue
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +08001016 if (status_filter is not None and
1017 test.get_state().status not in status_filter):
Jon Salz0697cbf2012-07-04 15:14:04 +08001018 continue
1019 self.tests_to_run.append(test)
Ricky Liang4bff3e32014-02-20 18:46:11 +08001020 if subtrees:
1021 self.set_active_run_state()
Jon Salz0697cbf2012-07-04 15:14:04 +08001022 self.run_next_test()
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001023
Jon Salz0697cbf2012-07-04 15:14:04 +08001024 def reap_completed_tests(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001025 """Removes completed tests from the set of active tests.
Jon Salz0697cbf2012-07-04 15:14:04 +08001026
1027 Also updates the visible test if it was reaped.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001028 """
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001029 test_completed = False
Jon Salz0697cbf2012-07-04 15:14:04 +08001030 for t, v in dict(self.invocations).iteritems():
1031 if v.is_completed():
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001032 test_completed = True
Jon Salz1acc8742012-07-17 17:45:55 +08001033 new_state = t.update_state(**v.update_state_on_completion)
Jon Salz0697cbf2012-07-04 15:14:04 +08001034 del self.invocations[t]
1035
Johny Lin62ed2a32015-05-13 11:57:12 +08001036 # Stop on failure if flag is true and there is no retry chances.
Chun-Ta Lin54e17e42012-09-06 22:05:13 +08001037 if (self.test_list.options.stop_on_failure and
Johny Lin62ed2a32015-05-13 11:57:12 +08001038 new_state.retries_left < 0 and
Chun-Ta Lin54e17e42012-09-06 22:05:13 +08001039 new_state.status == TestState.FAILED):
1040 # Clean all the tests to cause goofy to stop.
1041 self.tests_to_run = []
Ricky Liang45c73e72015-01-15 15:00:30 +08001042 factory.console.info('Stop on failure triggered. Empty the queue.')
Chun-Ta Lin54e17e42012-09-06 22:05:13 +08001043
Jon Salz1acc8742012-07-17 17:45:55 +08001044 if new_state.iterations_left and new_state.status == TestState.PASSED:
1045 # Play it again, Sam!
1046 self._run_test(t)
Cheng-Yi Chiangce05c002013-04-04 02:13:17 +08001047 # new_state.retries_left is obtained after update.
1048 # For retries_left == 0, test can still be run for the last time.
1049 elif (new_state.retries_left >= 0 and
1050 new_state.status == TestState.FAILED):
1051 # Still have to retry, Sam!
1052 self._run_test(t)
Jon Salz1acc8742012-07-17 17:45:55 +08001053
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001054 if test_completed:
Vic Yangf01c59f2013-04-19 17:37:56 +08001055 self.log_watcher.KickWatchThread()
Cheng-Yi Chiang5ac22ca2013-04-12 17:45:26 +08001056
Jon Salz0697cbf2012-07-04 15:14:04 +08001057 if (self.visible_test is None or
Jon Salz85a39882012-07-05 16:45:04 +08001058 self.visible_test not in self.invocations):
Jon Salz0697cbf2012-07-04 15:14:04 +08001059 self.set_visible_test(None)
1060 # Make the first running test, if any, the visible test
1061 for t in self.test_list.walk():
1062 if t in self.invocations:
1063 self.set_visible_test(t)
1064 break
1065
Jon Salz6dc031d2013-06-19 13:06:23 +08001066 def kill_active_tests(self, abort, root=None, reason=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001067 """Kills and waits for all active tests.
Jon Salz0697cbf2012-07-04 15:14:04 +08001068
Jon Salz85a39882012-07-05 16:45:04 +08001069 Args:
1070 abort: True to change state of killed tests to FAILED, False for
Jon Salz0697cbf2012-07-04 15:14:04 +08001071 UNTESTED.
Jon Salz85a39882012-07-05 16:45:04 +08001072 root: If set, only kills tests with root as an ancestor.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001073 reason: If set, the abort reason.
1074 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001075 self.reap_completed_tests()
1076 for test, invoc in self.invocations.items():
Jon Salz85a39882012-07-05 16:45:04 +08001077 if root and not test.has_ancestor(root):
1078 continue
1079
Ricky Liang45c73e72015-01-15 15:00:30 +08001080 factory.console.info('Killing active test %s...', test.path)
Jon Salz6dc031d2013-06-19 13:06:23 +08001081 invoc.abort_and_join(reason)
Ricky Liang45c73e72015-01-15 15:00:30 +08001082 factory.console.info('Killed %s', test.path)
Jon Salz1acc8742012-07-17 17:45:55 +08001083 test.update_state(**invoc.update_state_on_completion)
Jon Salz0697cbf2012-07-04 15:14:04 +08001084 del self.invocations[test]
Jon Salz1acc8742012-07-17 17:45:55 +08001085
Jon Salz0697cbf2012-07-04 15:14:04 +08001086 if not abort:
1087 test.update_state(status=TestState.UNTESTED)
1088 self.reap_completed_tests()
1089
Jon Salz6dc031d2013-06-19 13:06:23 +08001090 def stop(self, root=None, fail=False, reason=None):
1091 self.kill_active_tests(fail, root, reason)
Jon Salz85a39882012-07-05 16:45:04 +08001092 # Remove any tests in the run queue under the root.
1093 self.tests_to_run = deque([x for x in self.tests_to_run
1094 if root and not x.has_ancestor(root)])
1095 self.run_next_test()
Jon Salz0697cbf2012-07-04 15:14:04 +08001096
Jon Salz4712ac72013-02-07 17:12:05 +08001097 def clear_state(self, root=None):
Jon Salzd7550792013-07-12 05:49:27 +08001098 if root is None:
1099 root = self.test_list
Jon Salz6dc031d2013-06-19 13:06:23 +08001100 self.stop(root, reason='Clearing test state')
Jon Salz4712ac72013-02-07 17:12:05 +08001101 for f in root.walk():
1102 if f.is_leaf():
1103 f.update_state(status=TestState.UNTESTED)
1104
Jon Salz6dc031d2013-06-19 13:06:23 +08001105 def abort_active_tests(self, reason=None):
1106 self.kill_active_tests(True, reason=reason)
Jon Salz0697cbf2012-07-04 15:14:04 +08001107
1108 def main(self):
Jon Salzeff94182013-06-19 15:06:28 +08001109 syslog.openlog('goofy')
1110
Jon Salz0697cbf2012-07-04 15:14:04 +08001111 try:
Jon Salzd7550792013-07-12 05:49:27 +08001112 self.status = Status.INITIALIZING
Jon Salz0697cbf2012-07-04 15:14:04 +08001113 self.init()
1114 self.event_log.Log('goofy_init',
Ricky Liang45c73e72015-01-15 15:00:30 +08001115 success=True)
Jon Salz0697cbf2012-07-04 15:14:04 +08001116 except:
1117 if self.event_log:
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001118 try:
Jon Salz0697cbf2012-07-04 15:14:04 +08001119 self.event_log.Log('goofy_init',
Ricky Liang45c73e72015-01-15 15:00:30 +08001120 success=False,
1121 trace=traceback.format_exc())
Jon Salz0697cbf2012-07-04 15:14:04 +08001122 except: # pylint: disable=W0702
1123 pass
1124 raise
1125
Jon Salzd7550792013-07-12 05:49:27 +08001126 self.status = Status.RUNNING
Jon Salzeff94182013-06-19 15:06:28 +08001127 syslog.syslog('Goofy (factory test harness) starting')
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001128 syslog.syslog('Boot sequence = %d' % GetBootSequence())
Jon Salz0697cbf2012-07-04 15:14:04 +08001129 self.run()
1130
1131 def update_system_info(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001132 """Updates system info."""
Hung-Te Line594e5d2015-12-16 02:36:05 +08001133 info = self.dut.info.GetAll()
1134 self.state_instance.set_shared_data('system_info', info)
Jon Salz0697cbf2012-07-04 15:14:04 +08001135 self.event_client.post_event(Event(Event.Type.SYSTEM_INFO,
Hung-Te Line594e5d2015-12-16 02:36:05 +08001136 system_info=info))
1137 logging.info('System info: %r', info)
Jon Salz0697cbf2012-07-04 15:14:04 +08001138
Jon Salzeb42f0d2012-07-27 19:14:04 +08001139 def update_factory(self, auto_run_on_restart=False, post_update_hook=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001140 """Commences updating factory software.
Jon Salzeb42f0d2012-07-27 19:14:04 +08001141
1142 Args:
1143 auto_run_on_restart: Auto-run when the machine comes back up.
1144 post_update_hook: Code to call after update but immediately before
1145 restart.
1146
1147 Returns:
1148 Never if the update was successful (we just reboot).
1149 False if the update was unnecessary (no update available).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001150 """
Jon Salz6dc031d2013-06-19 13:06:23 +08001151 self.kill_active_tests(False, reason='Factory software update')
Jon Salza6711d72012-07-18 14:33:03 +08001152 self.cancel_pending_tests()
Jon Salz0697cbf2012-07-04 15:14:04 +08001153
Jon Salz5c344f62012-07-13 14:31:16 +08001154 def pre_update_hook():
1155 if auto_run_on_restart:
1156 self.state_instance.set_shared_data('tests_after_shutdown',
1157 FORCE_AUTO_RUN)
1158 self.state_instance.close()
1159
Jon Salzeb42f0d2012-07-27 19:14:04 +08001160 if updater.TryUpdate(pre_update_hook=pre_update_hook):
1161 if post_update_hook:
1162 post_update_hook()
1163 self.env.shutdown('reboot')
Jon Salz0697cbf2012-07-04 15:14:04 +08001164
Ricky Liang8fecf412014-05-22 10:56:14 +08001165 def handle_sigint(self, dummy_signum, dummy_frame): # pylint: disable=W0613
Jon Salz77c151e2012-08-28 07:20:37 +08001166 logging.error('Received SIGINT')
Peter Ammon1e1ec572014-06-26 17:56:32 -07001167 self.run_enqueue(None)
Jon Salz77c151e2012-08-28 07:20:37 +08001168 raise KeyboardInterrupt()
1169
Ricky Liang8fecf412014-05-22 10:56:14 +08001170 def handle_sigterm(self, dummy_signum, dummy_frame): # pylint: disable=W0613
1171 logging.error('Received SIGTERM')
Hung-Te Lin94ca4742014-07-09 20:13:50 +08001172 self.env.terminate()
1173 self.run_queue.put(None)
Ricky Liang8fecf412014-05-22 10:56:14 +08001174 raise RuntimeError('Received SIGTERM')
1175
Jon Salze12c2b32013-06-25 16:24:34 +08001176 def find_kcrashes(self):
1177 """Finds kcrash files, logs them, and marks them as seen."""
1178 seen_crashes = set(
1179 self.state_instance.get_shared_data('seen_crashes', optional=True)
1180 or [])
1181
1182 for path in glob.glob('/var/spool/crash/*'):
1183 if not os.path.isfile(path):
1184 continue
1185 if path in seen_crashes:
1186 continue
1187 try:
1188 stat = os.stat(path)
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001189 mtime = time_utils.TimeString(stat.st_mtime)
Jon Salze12c2b32013-06-25 16:24:34 +08001190 logging.info(
1191 'Found new crash file %s (%d bytes at %s)',
1192 path, stat.st_size, mtime)
1193 extra_log_args = {}
1194
1195 try:
1196 _, ext = os.path.splitext(path)
1197 if ext in ['.kcrash', '.meta']:
1198 ext = ext.replace('.', '')
1199 with open(path) as f:
1200 data = f.read(MAX_CRASH_FILE_SIZE)
1201 tell = f.tell()
1202 logging.info(
1203 'Contents of %s%s:%s',
1204 path,
1205 ('' if tell == stat.st_size
1206 else '(truncated to %d bytes)' % MAX_CRASH_FILE_SIZE),
1207 ('\n' + data).replace('\n', '\n ' + ext + '> '))
1208 extra_log_args['data'] = data
1209
1210 # Copy to /var/factory/kcrash for posterity
1211 kcrash_dir = factory.get_factory_root('kcrash')
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001212 file_utils.TryMakeDirs(kcrash_dir)
Jon Salze12c2b32013-06-25 16:24:34 +08001213 shutil.copy(path, kcrash_dir)
1214 logging.info('Copied to %s',
1215 os.path.join(kcrash_dir, os.path.basename(path)))
1216 finally:
1217 # Even if something goes wrong with the above, still try to
1218 # log to event log
1219 self.event_log.Log('crash_file',
1220 path=path, size=stat.st_size, mtime=mtime,
1221 **extra_log_args)
1222 except: # pylint: disable=W0702
1223 logging.exception('Unable to handle crash files %s', path)
1224 seen_crashes.add(path)
1225
1226 self.state_instance.set_shared_data('seen_crashes', list(seen_crashes))
1227
Jon Salz128b0932013-07-03 16:55:26 +08001228 def GetTestList(self, test_list_id):
1229 """Returns the test list with the given ID.
1230
1231 Raises:
1232 TestListError: The test list ID is not valid.
1233 """
1234 try:
1235 return self.test_lists[test_list_id]
1236 except KeyError:
1237 raise test_lists.TestListError(
1238 '%r is not a valid test list ID (available IDs are [%s])' % (
1239 test_list_id, ', '.join(sorted(self.test_lists.keys()))))
1240
1241 def InitTestLists(self):
Joel Kitching50a63ea2016-02-22 13:15:09 +08001242 """Reads in all test lists and sets the active test list.
1243
1244 Returns:
1245 True if the active test list could be set, False if failed.
1246 """
1247 startup_errors = []
1248 self.test_lists, failed_files = test_lists.BuildAllTestLists(
Ricky Liang27051552014-05-04 14:22:26 +08001249 force_generic=(self.options.automation_mode is not None))
Jon Salzd7550792013-07-12 05:49:27 +08001250 logging.info('Loaded test lists: [%s]',
1251 test_lists.DescribeTestLists(self.test_lists))
Jon Salz128b0932013-07-03 16:55:26 +08001252
Joel Kitching50a63ea2016-02-22 13:15:09 +08001253 # Check for any syntax errors in test list files.
1254 if failed_files:
1255 logging.info('Failed test list files: [%s]',
1256 ' '.join(failed_files.keys()))
1257 for f, exc_info in failed_files.iteritems():
1258 logging.error('Error in test list file: %s', f,
1259 exc_info=exc_info)
1260
1261 # Limit the stack trace to the very last entry.
1262 exc_type, exc_value, exc_traceback = exc_info
1263 while exc_traceback and exc_traceback.tb_next:
1264 exc_traceback = exc_traceback.tb_next
1265
1266 exc_string = ''.join(
1267 traceback.format_exception(
1268 exc_type, exc_value, exc_traceback)).rstrip()
1269 startup_errors.append('Error in test list file (%s):\n%s'
1270 % (f, exc_string))
1271
Jon Salz128b0932013-07-03 16:55:26 +08001272 if not self.options.test_list:
1273 self.options.test_list = test_lists.GetActiveTestListId()
1274
Joel Kitching50a63ea2016-02-22 13:15:09 +08001275 # Check for a non-existent test list ID.
1276 try:
1277 if os.sep in self.options.test_list:
1278 # It's a path pointing to an old-style test list; use it.
1279 self.test_list = factory.read_test_list(self.options.test_list)
1280 else:
1281 self.test_list = self.GetTestList(self.options.test_list)
1282 logging.info('Active test list: %s', self.test_list.test_list_id)
1283 except test_lists.TestListError as e:
1284 logging.exception('Invalid active test list: %s',
1285 self.options.test_list)
1286 startup_errors.append(e.message)
Jon Salz128b0932013-07-03 16:55:26 +08001287
Joel Kitching50a63ea2016-02-22 13:15:09 +08001288 # We may have failed loading the active test list.
1289 if self.test_list:
1290 if isinstance(self.test_list, test_lists.OldStyleTestList):
1291 # Actually load it in. (See OldStyleTestList for an explanation
1292 # of why this is necessary.)
1293 self.test_list = self.test_list.Load()
Jon Salz128b0932013-07-03 16:55:26 +08001294
Joel Kitching50a63ea2016-02-22 13:15:09 +08001295 self.test_list.state_instance = self.state_instance
Jon Salz128b0932013-07-03 16:55:26 +08001296
Joel Kitching50a63ea2016-02-22 13:15:09 +08001297 # Prepare DUT link.
1298 if self.test_list.options.dut_options:
1299 logging.info('dut_options set by %s: %r', self.test_list.test_list_id,
1300 self.test_list.options.dut_options)
1301 dut_utils.PrepareLink(**self.test_list.options.dut_options)
Wei-Han Chene8a025f2016-01-14 16:42:02 +08001302
Joel Kitching50a63ea2016-02-22 13:15:09 +08001303 # Show all startup errors.
1304 if startup_errors:
1305 self.state_instance.set_shared_data(
1306 'startup_error', '\n\n'.join(startup_errors))
1307
1308 # Only return False if failed to load the active test list.
1309 return bool(self.test_list)
Jon Salz128b0932013-07-03 16:55:26 +08001310
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001311 def init_hooks(self):
1312 """Initializes hooks.
1313
1314 Must run after self.test_list ready.
1315 """
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001316 module, cls = self.test_list.options.hooks_class.rsplit('.', 1)
1317 self.hooks = getattr(__import__(module, fromlist=[cls]), cls)()
1318 assert isinstance(self.hooks, factory.Hooks), (
Ricky Liang45c73e72015-01-15 15:00:30 +08001319 'hooks should be of type Hooks but is %r' % type(self.hooks))
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001320 self.hooks.test_list = self.test_list
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001321 self.hooks.OnCreatedTestList()
Shuo-Peng Liao52b90da2013-06-30 17:00:06 +08001322
Vic Yanga3cecf82014-12-26 00:44:21 -08001323 def init_ui(self):
1324 """Initialize UI."""
1325 self._ui_initialized = True
1326 if self.options.ui == 'chrome':
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001327 if self.options.monolithic:
Hung-Te Lin7bd55312014-12-30 16:43:36 +08001328 self.env.launch_chrome()
1329 else:
1330 # The presenter is responsible for launching Chrome. Let's just
1331 # wait here.
1332 self.env.controller_ready_for_ui()
Vic Yanga3cecf82014-12-26 00:44:21 -08001333 logging.info('Waiting for a web socket connection')
1334 self.web_socket_manager.wait()
1335
1336 # Wait for the test widget size to be set; this is done in
1337 # an asynchronous RPC so there is a small chance that the
1338 # web socket might be opened first.
1339 for _ in range(100): # 10 s
1340 try:
1341 if self.state_instance.get_shared_data('test_widget_size'):
1342 break
1343 except KeyError:
1344 pass # Retry
1345 time.sleep(0.1) # 100 ms
1346 else:
1347 logging.warn('Never received test_widget_size from UI')
1348
Jon Salz0697cbf2012-07-04 15:14:04 +08001349 def init(self, args=None, env=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001350 """Initializes Goofy.
Jon Salz0697cbf2012-07-04 15:14:04 +08001351
1352 Args:
1353 args: A list of command-line arguments. Uses sys.argv if
1354 args is None.
1355 env: An Environment instance to use (or None to choose
1356 FakeChrootEnvironment or DUTEnvironment as appropriate).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001357 """
Jon Salz0697cbf2012-07-04 15:14:04 +08001358 parser = OptionParser()
1359 parser.add_option('-v', '--verbose', dest='verbose',
Jon Salz8fa8e832012-07-13 19:04:09 +08001360 action='store_true',
1361 help='Enable debug logging')
Jon Salz0697cbf2012-07-04 15:14:04 +08001362 parser.add_option('--print_test_list', dest='print_test_list',
Jon Salz8fa8e832012-07-13 19:04:09 +08001363 metavar='FILE',
1364 help='Read and print test list FILE, and exit')
Jon Salz0697cbf2012-07-04 15:14:04 +08001365 parser.add_option('--restart', dest='restart',
Jon Salz8fa8e832012-07-13 19:04:09 +08001366 action='store_true',
1367 help='Clear all test state')
Jon Salz0697cbf2012-07-04 15:14:04 +08001368 parser.add_option('--ui', dest='ui', type='choice',
Jon Salz7b5482e2014-08-04 17:48:41 +08001369 choices=['none', 'chrome'],
Jon Salz2f881df2013-02-01 17:00:35 +08001370 default='chrome',
Jon Salz8fa8e832012-07-13 19:04:09 +08001371 help='UI to use')
Jon Salz0697cbf2012-07-04 15:14:04 +08001372 parser.add_option('--ui_scale_factor', dest='ui_scale_factor',
Jon Salz8fa8e832012-07-13 19:04:09 +08001373 type='int', default=1,
1374 help=('Factor by which to scale UI '
1375 '(Chrome UI only)'))
Jon Salz0697cbf2012-07-04 15:14:04 +08001376 parser.add_option('--test_list', dest='test_list',
Jon Salz8fa8e832012-07-13 19:04:09 +08001377 metavar='FILE',
1378 help='Use FILE as test list')
Jon Salzc79a9982012-08-30 04:42:01 +08001379 parser.add_option('--dummy_shopfloor', action='store_true',
1380 help='Use a dummy shopfloor server')
Hung-Te Lincc41d2a2014-10-29 13:35:20 +08001381 parser.add_option('--dummy_connection_manager', action='store_true',
1382 help='Use a dummy connection manager')
Ricky Liang6fe218c2013-12-27 15:17:17 +08001383 parser.add_option('--automation-mode',
1384 choices=[m.lower() for m in AutomationMode],
Ricky Liang45c73e72015-01-15 15:00:30 +08001385 default='none', help='Factory test automation mode.')
Ricky Liang117484a2014-04-14 11:14:41 +08001386 parser.add_option('--no-auto-run-on-start', dest='auto_run_on_start',
1387 action='store_false', default=True,
1388 help=('do not automatically run the test list on goofy '
1389 'start; this is only valid when factory test '
1390 'automation is enabled'))
Chun-Ta Lina8dd3172014-11-26 16:15:13 +08001391 parser.add_option('--handshake_timeout', dest='handshake_timeout',
1392 type='float', default=0.3,
1393 help=('RPC timeout when doing handshake between device '
1394 'and presenter.'))
Vic Yang7d693c42014-09-14 09:52:39 +08001395 parser.add_option('--standalone', dest='standalone',
1396 action='store_true', default=False,
1397 help=('Assume the presenter is running on the same '
1398 'machines.'))
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001399 parser.add_option('--monolithic', dest='monolithic',
1400 action='store_true', default=False,
1401 help='Run in monolithic mode (without presenter)')
Jon Salz0697cbf2012-07-04 15:14:04 +08001402 (self.options, self.args) = parser.parse_args(args)
1403
Hung-Te Lina846f602014-07-04 20:32:22 +08001404 signal.signal(signal.SIGINT, self.handle_sigint)
1405 # TODO(hungte) SIGTERM does not work properly without Telemetry and should
1406 # be fixed.
Hung-Te Lina846f602014-07-04 20:32:22 +08001407
Jon Salz46b89562012-07-05 11:49:22 +08001408 # Make sure factory directories exist.
1409 factory.get_log_root()
1410 factory.get_state_root()
1411 factory.get_test_data_root()
1412
Jon Salz0697cbf2012-07-04 15:14:04 +08001413 global _inited_logging # pylint: disable=W0603
1414 if not _inited_logging:
1415 factory.init_logging('goofy', verbose=self.options.verbose)
1416 _inited_logging = True
Jon Salz8fa8e832012-07-13 19:04:09 +08001417
Jon Salz0f996602012-10-03 15:26:48 +08001418 if self.options.print_test_list:
Joel Kitchingb85ed7f2014-10-08 18:24:39 +08001419 print(factory.read_test_list(
1420 self.options.print_test_list).__repr__(recursive=True))
Jon Salz0f996602012-10-03 15:26:48 +08001421 sys.exit(0)
1422
Jon Salzee85d522012-07-17 14:34:46 +08001423 event_log.IncrementBootSequence()
Jon Salzd15bbcf2013-05-21 17:33:57 +08001424 # Don't defer logging the initial event, so we can make sure
1425 # that device_id, reimage_id, etc. are all set up.
1426 self.event_log = EventLog('goofy', defer=False)
Jon Salz0697cbf2012-07-04 15:14:04 +08001427
Jon Salz0697cbf2012-07-04 15:14:04 +08001428 if env:
1429 self.env = env
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001430 elif sys_utils.InChroot():
Jon Salz0697cbf2012-07-04 15:14:04 +08001431 self.env = test_environment.FakeChrootEnvironment()
1432 logging.warn(
Ricky Liang45c73e72015-01-15 15:00:30 +08001433 'Using chroot environment: will not actually run autotests')
Hung-Te Lina846f602014-07-04 20:32:22 +08001434 elif self.options.ui == 'chrome':
Ricky Liang09d66d82014-09-25 11:20:54 +08001435 self.env = test_environment.DUTEnvironment()
Jon Salz0697cbf2012-07-04 15:14:04 +08001436 self.env.goofy = self
Vic Yanga4931152014-08-11 16:36:24 -07001437 # web_socket_manager will be initialized later
1438 # pylint: disable=W0108
1439 self.env.has_sockets = lambda: self.web_socket_manager.has_sockets()
Jon Salz0697cbf2012-07-04 15:14:04 +08001440
1441 if self.options.restart:
1442 state.clear_state()
1443
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001444 if self.options.ui_scale_factor != 1 and sys_utils.InQEMU():
Jon Salz0697cbf2012-07-04 15:14:04 +08001445 logging.warn(
Ricky Liang45c73e72015-01-15 15:00:30 +08001446 'In QEMU; ignoring ui_scale_factor argument')
Jon Salz0697cbf2012-07-04 15:14:04 +08001447 self.options.ui_scale_factor = 1
1448
1449 logging.info('Started')
1450
Hung-Te Lin8f6a3782015-01-06 22:58:32 +08001451 if not self.options.monolithic:
Hung-Te Lin7bd55312014-12-30 16:43:36 +08001452 self.link_manager = PresenterLinkManager(
1453 check_interval=1,
1454 handshake_timeout=self.options.handshake_timeout,
1455 standalone=self.options.standalone)
Peter Ammon1e1ec572014-06-26 17:56:32 -07001456
Jon Salz0697cbf2012-07-04 15:14:04 +08001457 self.start_state_server()
1458 self.state_instance.set_shared_data('hwid_cfg', get_hwid_cfg())
1459 self.state_instance.set_shared_data('ui_scale_factor',
Ricky Liang09216dc2013-02-22 17:26:45 +08001460 self.options.ui_scale_factor)
Jon Salz0697cbf2012-07-04 15:14:04 +08001461 self.last_shutdown_time = (
Ricky Liang45c73e72015-01-15 15:00:30 +08001462 self.state_instance.get_shared_data('shutdown_time', optional=True))
Jon Salz0697cbf2012-07-04 15:14:04 +08001463 self.state_instance.del_shared_data('shutdown_time', optional=True)
Jon Salzb19ea072013-02-07 16:35:00 +08001464 self.state_instance.del_shared_data('startup_error', optional=True)
Jon Salz0697cbf2012-07-04 15:14:04 +08001465
Ricky Liang6fe218c2013-12-27 15:17:17 +08001466 self.options.automation_mode = ParseAutomationMode(
1467 self.options.automation_mode)
1468 self.state_instance.set_shared_data('automation_mode',
1469 self.options.automation_mode)
1470 self.state_instance.set_shared_data(
1471 'automation_mode_prompt',
1472 AutomationModePrompt[self.options.automation_mode])
1473
Joel Kitching50a63ea2016-02-22 13:15:09 +08001474 success = False
1475 exc_info = None
Jon Salz128b0932013-07-03 16:55:26 +08001476 try:
Joel Kitching50a63ea2016-02-22 13:15:09 +08001477 success = self.InitTestLists()
Jon Salz128b0932013-07-03 16:55:26 +08001478 except: # pylint: disable=W0702
Joel Kitching50a63ea2016-02-22 13:15:09 +08001479 exc_info = sys.exc_info()
1480
1481 if not success:
1482 if exc_info:
1483 logging.exception('Unable to initialize test lists')
1484 self.state_instance.set_shared_data(
1485 'startup_error',
1486 'Unable to initialize test lists\n%s' % (
1487 traceback.format_exc()))
Jon Salzb19ea072013-02-07 16:35:00 +08001488 if self.options.ui == 'chrome':
1489 # Create an empty test list with default options so that the rest of
1490 # startup can proceed.
1491 self.test_list = factory.FactoryTestList(
1492 [], self.state_instance, factory.Options())
1493 else:
1494 # Bail with an error; no point in starting up.
1495 sys.exit('No valid test list; exiting.')
1496
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001497 self.init_hooks()
1498
Jon Salz822838b2013-03-25 17:32:33 +08001499 if self.test_list.options.clear_state_on_start:
1500 self.state_instance.clear_test_state()
1501
Jon Salz670ce062014-05-16 15:53:50 +08001502 # If the phase is invalid, this will raise a ValueError.
1503 phase.SetPersistentPhase(self.test_list.options.phase)
1504
Dean Liao85ca86f2014-11-03 12:28:08 +08001505 # For netboot firmware, mainfw_type should be 'netboot'.
Hung-Te Line594e5d2015-12-16 02:36:05 +08001506 if (self.dut.info.mainfw_type != 'nonchrome' and
1507 self.dut.info.firmware_version is None):
Ricky Liang45c73e72015-01-15 15:00:30 +08001508 self.state_instance.set_shared_data(
1509 'startup_error',
Vic Yang9bd4f772013-06-04 17:34:00 +08001510 'Netboot firmware detected\n'
1511 'Connect Ethernet and reboot to re-image.\n'
1512 u'侦测到网路开机固件\n'
1513 u'请连接乙太网并重启')
1514
Jon Salz0697cbf2012-07-04 15:14:04 +08001515 if not self.state_instance.has_shared_data('ui_lang'):
1516 self.state_instance.set_shared_data('ui_lang',
Ricky Liang45c73e72015-01-15 15:00:30 +08001517 self.test_list.options.ui_lang)
Jon Salz0697cbf2012-07-04 15:14:04 +08001518 self.state_instance.set_shared_data(
Ricky Liang45c73e72015-01-15 15:00:30 +08001519 'test_list_options',
1520 self.test_list.options.__dict__)
Jon Salz0697cbf2012-07-04 15:14:04 +08001521 self.state_instance.test_list = self.test_list
1522
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001523 self.check_log_rotation()
Jon Salz83ef34b2012-11-01 19:46:35 +08001524
Jon Salz23926422012-09-01 03:38:13 +08001525 if self.options.dummy_shopfloor:
Ricky Liang45c73e72015-01-15 15:00:30 +08001526 os.environ[shopfloor.SHOPFLOOR_SERVER_ENV_VAR_NAME] = (
1527 'http://%s:%d/' %
Joel Kitchingb85ed7f2014-10-08 18:24:39 +08001528 (net_utils.LOCALHOST, shopfloor.DEFAULT_SERVER_PORT))
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001529 self.dummy_shopfloor = process_utils.Spawn(
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +08001530 [os.path.join(paths.FACTORY_PATH, 'bin', 'shopfloor_server'),
Jon Salz23926422012-09-01 03:38:13 +08001531 '--dummy'])
1532 elif self.test_list.options.shopfloor_server_url:
1533 shopfloor.set_server_url(self.test_list.options.shopfloor_server_url)
Jon Salz2bf2f6b2013-03-28 18:49:26 +08001534 shopfloor.set_enabled(True)
Jon Salz23926422012-09-01 03:38:13 +08001535
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001536 if self.test_list.options.time_sanitizer and not sys_utils.InChroot():
Jon Salz8fa8e832012-07-13 19:04:09 +08001537 self.time_sanitizer = time_sanitizer.TimeSanitizer(
Ricky Liang45c73e72015-01-15 15:00:30 +08001538 base_time=time_sanitizer.GetBaseTimeFromFile(
1539 # lsb-factory is written by the factory install shim during
1540 # installation, so it should have a good time obtained from
1541 # the mini-Omaha server. If it's not available, we'll use
1542 # /etc/lsb-factory (which will be much older, but reasonably
1543 # sane) and rely on a shopfloor sync to set a more accurate
1544 # time.
1545 '/usr/local/etc/lsb-factory',
1546 '/etc/lsb-release'))
Jon Salz8fa8e832012-07-13 19:04:09 +08001547 self.time_sanitizer.RunOnce()
1548
Vic Yangd8990da2013-06-27 16:57:43 +08001549 if self.test_list.options.check_cpu_usage_period_secs:
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001550 self.cpu_usage_watcher = process_utils.Spawn(
Ricky Liang45c73e72015-01-15 15:00:30 +08001551 ['py/tools/cpu_usage_monitor.py', '-p',
1552 str(self.test_list.options.check_cpu_usage_period_secs)],
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +08001553 cwd=paths.FACTORY_PATH)
Vic Yangd8990da2013-06-27 16:57:43 +08001554
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001555 # Enable thermal monitor
1556 if self.test_list.options.thermal_monitor_period_secs > 0:
Hung-Te Lin23cb7612016-01-19 19:19:32 +08001557 self.thermal_watcher = process_utils.Spawn(
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001558 ['py/tools/thermal_monitor.py',
1559 '-p', str(self.test_list.options.thermal_monitor_period_secs),
1560 '-d', str(self.test_list.options.thermal_monitor_delta)],
Wei-Han Chen2ebb92d2016-01-12 14:51:41 +08001561 cwd=paths.FACTORY_PATH)
Chun-Ta Lin5d12b592015-06-30 00:54:23 -07001562
Jon Salz0697cbf2012-07-04 15:14:04 +08001563 self.init_states()
1564 self.start_event_server()
Wei-Ning Huang38b75f02015-02-25 18:25:14 +08001565 self.start_terminal_server()
Hung-Te Lincc41d2a2014-10-29 13:35:20 +08001566
1567 if self.options.dummy_connection_manager:
1568 # Override network manager creation to dummy implmenetation.
1569 logging.info('Using dummy network manager (--dummy_connection_manager).')
1570 self.connection_manager = connection_manager.DummyConnectionManager()
1571 else:
1572 self.connection_manager = self.env.create_connection_manager(
1573 self.test_list.options.wlans,
Mao Huang4340c632015-04-14 14:35:22 +08001574 self.test_list.options.scan_wifi_period_secs,
1575 self.test_list.options.override_blacklisted_network_devices)
Hung-Te Lincc41d2a2014-10-29 13:35:20 +08001576
Jon Salz0697cbf2012-07-04 15:14:04 +08001577 # Note that we create a log watcher even if
1578 # sync_event_log_period_secs isn't set (no background
1579 # syncing), since we may use it to flush event logs as well.
1580 self.log_watcher = EventLogWatcher(
Ricky Liang45c73e72015-01-15 15:00:30 +08001581 self.test_list.options.sync_event_log_period_secs,
1582 event_log_db_file=None,
1583 handle_event_logs_callback=self.handle_event_logs)
Jon Salz0697cbf2012-07-04 15:14:04 +08001584 if self.test_list.options.sync_event_log_period_secs:
1585 self.log_watcher.StartWatchThread()
1586
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001587 # Creates a system log manager to scan logs periocially.
1588 # A scan includes clearing logs and optionally syncing logs if
1589 # enable_syng_log is True. We kick it to sync logs.
1590 self.system_log_manager = SystemLogManager(
Ricky Liang45c73e72015-01-15 15:00:30 +08001591 sync_log_paths=self.test_list.options.sync_log_paths,
1592 sync_log_period_secs=self.test_list.options.sync_log_period_secs,
1593 scan_log_period_secs=self.test_list.options.scan_log_period_secs,
1594 clear_log_paths=self.test_list.options.clear_log_paths,
1595 clear_log_excluded_paths=self.test_list.options.clear_log_excluded_paths)
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001596 self.system_log_manager.Start()
Cheng-Yi Chiang344b10f2013-05-03 16:44:03 +08001597
Jon Salz0697cbf2012-07-04 15:14:04 +08001598 self.update_system_info()
1599
Vic Yang4953fc12012-07-26 16:19:53 +08001600 assert ((self.test_list.options.min_charge_pct is None) ==
1601 (self.test_list.options.max_charge_pct is None))
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001602 if sys_utils.InChroot():
Vic Yange83d9a12013-04-19 20:00:20 +08001603 logging.info('In chroot, ignoring charge manager and charge state')
Ricky Liangc392a1c2014-06-20 18:24:59 +08001604 elif (self.test_list.options.enable_charge_manager and
1605 self.test_list.options.min_charge_pct is not None):
Vic Yang4953fc12012-07-26 16:19:53 +08001606 self.charge_manager = ChargeManager(self.test_list.options.min_charge_pct,
1607 self.test_list.options.max_charge_pct)
Hung-Te Linc17b3d82015-12-15 15:26:08 +08001608 self.dut.status.Overrides('charge_manager', self.charge_manager)
Cheng-Yi Chiangd8186952013-04-04 23:41:14 +08001609 else:
1610 # Goofy should set charger state to charge if charge_manager is disabled.
Dean Liao88b93192014-10-23 19:37:41 +08001611 self.charge()
Vic Yang4953fc12012-07-26 16:19:53 +08001612
Vic Yang6cee2472014-10-22 17:18:52 -07001613 if CoreDumpManager.CoreDumpEnabled():
1614 self.core_dump_manager = CoreDumpManager(
1615 self.test_list.options.core_dump_watchlist)
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001616
Jon Salz0697cbf2012-07-04 15:14:04 +08001617 os.environ['CROS_FACTORY'] = '1'
1618 os.environ['CROS_DISABLE_SITE_SYSINFO'] = '1'
1619
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001620 if not sys_utils.InChroot() and self.test_list.options.use_cpufreq_manager:
Ricky Liangecddbd42014-07-24 11:32:10 +08001621 logging.info('Enabling CPU frequency manager')
Jon Salzddf0d052013-06-18 12:52:44 +08001622 self.cpufreq_manager = CpufreqManager(event_log=self.event_log)
Jon Salzce6a7f82013-06-10 18:22:54 +08001623
Justin Chuang31b02432013-06-27 15:16:51 +08001624 # Startup hooks may want to skip some tests.
1625 self.update_skipped_tests()
Jon Salz416f9cc2013-05-10 18:32:50 +08001626
Jon Salze12c2b32013-06-25 16:24:34 +08001627 self.find_kcrashes()
1628
Shuo-Peng Liao268b40b2013-07-01 15:58:59 +08001629 # Should not move earlier.
1630 self.hooks.OnStartup()
1631
Ricky Liang36512a32014-07-25 11:47:04 +08001632 # Only after this point the Goofy backend is ready for UI connection.
1633 self.ready_for_ui_connection = True
1634
Ricky Liang650f6bf2012-09-28 13:22:54 +08001635 # Create download path for autotest beforehand or autotests run at
1636 # the same time might fail due to race condition.
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001637 if not sys_utils.InChroot():
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001638 file_utils.TryMakeDirs(os.path.join('/usr/local/autotest', 'tests',
1639 'download'))
Ricky Liang650f6bf2012-09-28 13:22:54 +08001640
Jon Salz0697cbf2012-07-04 15:14:04 +08001641 def state_change_callback(test, test_state):
1642 self.event_client.post_event(
Ricky Liang4bff3e32014-02-20 18:46:11 +08001643 Event(Event.Type.STATE_CHANGE, path=test.path, state=test_state))
Jon Salz0697cbf2012-07-04 15:14:04 +08001644 self.test_list.state_change_callback = state_change_callback
Jon Salz73e0fd02012-04-04 11:46:38 +08001645
Vic Yange2c76a82014-10-30 12:48:19 -07001646 self.autotest_prespawner = prespawner.AutotestPrespawner()
1647 self.autotest_prespawner.start()
1648
1649 self.pytest_prespawner = prespawner.PytestPrespawner()
1650 self.pytest_prespawner.start()
Jon Salza6711d72012-07-18 14:33:03 +08001651
Ricky Liang48e47f92014-02-26 19:31:51 +08001652 tests_after_shutdown = self.state_instance.get_shared_data(
1653 'tests_after_shutdown', optional=True)
Jon Salz57717ca2012-04-04 16:47:25 +08001654
Jon Salz5c344f62012-07-13 14:31:16 +08001655 force_auto_run = (tests_after_shutdown == FORCE_AUTO_RUN)
1656 if not force_auto_run and tests_after_shutdown is not None:
Ricky Liang48e47f92014-02-26 19:31:51 +08001657 logging.info('Resuming tests after shutdown: %s', tests_after_shutdown)
Jon Salz0697cbf2012-07-04 15:14:04 +08001658 self.tests_to_run.extend(
Ricky Liang4bff3e32014-02-20 18:46:11 +08001659 self.test_list.lookup_path(t) for t in tests_after_shutdown)
Peter Ammon1e1ec572014-06-26 17:56:32 -07001660 self.run_enqueue(self.run_next_test)
Jon Salz0697cbf2012-07-04 15:14:04 +08001661 else:
Jon Salz5c344f62012-07-13 14:31:16 +08001662 if force_auto_run or self.test_list.options.auto_run_on_start:
Ricky Liang117484a2014-04-14 11:14:41 +08001663 # If automation mode is enabled, allow suppress auto_run_on_start.
1664 if (self.options.automation_mode == 'NONE' or
1665 self.options.auto_run_on_start):
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +08001666 status_filter = [TestState.UNTESTED]
1667 if self.test_list.options.retry_failed_on_start:
1668 status_filter.append(TestState.FAILED)
1669 self.run_enqueue(lambda: self.run_tests(self.test_list, status_filter))
Jon Salz5c344f62012-07-13 14:31:16 +08001670 self.state_instance.set_shared_data('tests_after_shutdown', None)
Ricky Liang4bff3e32014-02-20 18:46:11 +08001671 self.restore_active_run_state()
Hung-Te Linf2f78f72012-02-08 19:27:11 +08001672
Hung-Te Lin410f70a2015-12-15 14:53:42 +08001673 self.dut.hooks.OnTestStart()
Vic Yang08505c72015-01-06 17:01:53 -08001674
Dean Liao592e4d52013-01-10 20:06:39 +08001675 self.may_disable_cros_shortcut_keys()
1676
1677 def may_disable_cros_shortcut_keys(self):
1678 test_options = self.test_list.options
1679 if test_options.disable_cros_shortcut_keys:
1680 logging.info('Filter ChromeOS shortcut keys.')
1681 self.key_filter = KeyFilter(
1682 unmap_caps_lock=test_options.disable_caps_lock,
1683 caps_lock_keycode=test_options.caps_lock_keycode)
1684 self.key_filter.Start()
1685
Jon Salz0e6532d2012-10-25 16:30:11 +08001686 def _should_sync_time(self, foreground=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001687 """Returns True if we should attempt syncing time with shopfloor.
Jon Salz0e6532d2012-10-25 16:30:11 +08001688
1689 Args:
1690 foreground: If True, synchronizes even if background syncing
1691 is disabled (e.g., in explicit sync requests from the
1692 SyncShopfloor test).
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001693 """
Jon Salz0e6532d2012-10-25 16:30:11 +08001694 return ((foreground or
1695 self.test_list.options.sync_time_period_secs) and
Jon Salz54882d02012-08-31 01:57:54 +08001696 self.time_sanitizer and
1697 (not self.time_synced) and
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001698 (not sys_utils.InChroot()))
Jon Salz54882d02012-08-31 01:57:54 +08001699
Jon Salz0e6532d2012-10-25 16:30:11 +08001700 def sync_time_with_shopfloor_server(self, foreground=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001701 """Syncs time with shopfloor server, if not yet synced.
Jon Salz54882d02012-08-31 01:57:54 +08001702
Jon Salz0e6532d2012-10-25 16:30:11 +08001703 Args:
1704 foreground: If True, synchronizes even if background syncing
1705 is disabled (e.g., in explicit sync requests from the
1706 SyncShopfloor test).
1707
Jon Salz54882d02012-08-31 01:57:54 +08001708 Returns:
1709 False if no time sanitizer is available, or True if this sync (or a
1710 previous sync) succeeded.
1711
1712 Raises:
1713 Exception if unable to contact the shopfloor server.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001714 """
Jon Salz0e6532d2012-10-25 16:30:11 +08001715 if self._should_sync_time(foreground):
Jon Salz54882d02012-08-31 01:57:54 +08001716 self.time_sanitizer.SyncWithShopfloor()
1717 self.time_synced = True
1718 return self.time_synced
1719
Jon Salzb92c5112012-09-21 15:40:11 +08001720 def log_disk_space_stats(self):
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001721 if (sys_utils.InChroot() or
Jon Salz18e0e022013-06-11 17:13:39 +08001722 not self.test_list.options.log_disk_space_period_secs):
Jon Salzb92c5112012-09-21 15:40:11 +08001723 return
1724
1725 now = time.time()
1726 if (self.last_log_disk_space_time and
1727 now - self.last_log_disk_space_time <
1728 self.test_list.options.log_disk_space_period_secs):
1729 return
1730 self.last_log_disk_space_time = now
1731
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001732 # Upload event if stateful partition usage is above threshold.
1733 # Stateful partition is mounted on /usr/local, while
1734 # encrypted stateful partition is mounted on /var.
1735 # If there are too much logs in the factory process,
1736 # these two partitions might get full.
Jon Salzb92c5112012-09-21 15:40:11 +08001737 try:
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001738 vfs_infos = disk_space.GetAllVFSInfo()
1739 stateful_info, encrypted_info = None, None
1740 for vfs_info in vfs_infos.values():
1741 if '/usr/local' in vfs_info.mount_points:
1742 stateful_info = vfs_info
1743 if '/var' in vfs_info.mount_points:
1744 encrypted_info = vfs_info
1745
1746 stateful = disk_space.GetPartitionUsage(stateful_info)
1747 encrypted = disk_space.GetPartitionUsage(encrypted_info)
1748
Ricky Liang45c73e72015-01-15 15:00:30 +08001749 above_threshold = (
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001750 self.test_list.options.stateful_usage_threshold and
1751 max(stateful.bytes_used_pct,
1752 stateful.inodes_used_pct,
1753 encrypted.bytes_used_pct,
1754 encrypted.inodes_used_pct) >
Ricky Liang45c73e72015-01-15 15:00:30 +08001755 self.test_list.options.stateful_usage_threshold)
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001756
1757 if above_threshold:
1758 self.event_log.Log('stateful_partition_usage',
Ricky Liang45c73e72015-01-15 15:00:30 +08001759 partitions={
1760 'stateful': {
1761 'bytes_used_pct': FloatDigit(stateful.bytes_used_pct, 2),
1762 'inodes_used_pct': FloatDigit(stateful.inodes_used_pct, 2)},
1763 'encrypted_stateful': {
1764 'bytes_used_pct': FloatDigit(encrypted.bytes_used_pct, 2),
1765 'inodes_used_pct': FloatDigit(encrypted.inodes_used_pct, 2)}
1766 })
Cheng-Yi Chiang1b722322015-03-16 20:07:03 +08001767 self.log_watcher.KickWatchThread()
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001768 if (not sys_utils.InChroot() and
Cheng-Yi Chiang00798e72013-06-20 18:16:39 +08001769 self.test_list.options.stateful_usage_above_threshold_action):
Hung-Te Lin4e6357c2016-01-08 14:32:00 +08001770 process_utils.Spawn(
1771 self.test_list.options.stateful_usage_above_threshold_action,
1772 call=True)
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001773
1774 message = disk_space.FormatSpaceUsedAll(vfs_infos)
Jon Salz3c493bb2013-02-07 17:24:58 +08001775 if message != self.last_log_disk_space_message:
Cheng-Yi Chiangd0406522013-04-01 15:40:18 +08001776 if above_threshold:
1777 logging.warning(message)
1778 else:
1779 logging.info(message)
Jon Salz3c493bb2013-02-07 17:24:58 +08001780 self.last_log_disk_space_message = message
Jon Salzb92c5112012-09-21 15:40:11 +08001781 except: # pylint: disable=W0702
1782 logging.exception('Unable to get disk space used')
1783
Justin Chuang83813982013-05-13 01:26:32 +08001784 def check_battery(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001785 """Checks the current battery status.
Justin Chuang83813982013-05-13 01:26:32 +08001786
1787 Logs current battery charging level and status to log. If the battery level
1788 is lower below warning_low_battery_pct, send warning event to shopfloor.
1789 If the battery level is lower below critical_low_battery_pct, flush disks.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001790 """
Justin Chuang83813982013-05-13 01:26:32 +08001791 if not self.test_list.options.check_battery_period_secs:
1792 return
1793
1794 now = time.time()
1795 if (self.last_check_battery_time and
1796 now - self.last_check_battery_time <
1797 self.test_list.options.check_battery_period_secs):
1798 return
1799 self.last_check_battery_time = now
1800
1801 message = ''
1802 log_level = logging.INFO
1803 try:
Hung-Te Lin6a72c642015-12-13 22:09:09 +08001804 power = self.dut.power
Justin Chuang83813982013-05-13 01:26:32 +08001805 if not power.CheckBatteryPresent():
1806 message = 'Battery is not present'
1807 else:
1808 ac_present = power.CheckACPresent()
1809 charge_pct = power.GetChargePct(get_float=True)
1810 message = ('Current battery level %.1f%%, AC charger is %s' %
1811 (charge_pct, 'connected' if ac_present else 'disconnected'))
1812
1813 if charge_pct > self.test_list.options.critical_low_battery_pct:
1814 critical_low_battery = False
1815 else:
1816 critical_low_battery = True
1817 # Only sync disks when battery level is still above minimum
1818 # value. This can be used for offline analysis when shopfloor cannot
1819 # be connected.
1820 if charge_pct > MIN_BATTERY_LEVEL_FOR_DISK_SYNC:
1821 logging.warning('disk syncing for critical low battery situation')
1822 os.system('sync; sync; sync')
1823 else:
1824 logging.warning('disk syncing is cancelled '
1825 'because battery level is lower than %.1f',
1826 MIN_BATTERY_LEVEL_FOR_DISK_SYNC)
1827
1828 # Notify shopfloor server
1829 if (critical_low_battery or
1830 (not ac_present and
1831 charge_pct <= self.test_list.options.warning_low_battery_pct)):
1832 log_level = logging.WARNING
1833
1834 self.event_log.Log('low_battery',
1835 battery_level=charge_pct,
1836 charger_connected=ac_present,
1837 critical=critical_low_battery)
1838 self.log_watcher.KickWatchThread()
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001839 if self.test_list.options.enable_sync_log:
1840 self.system_log_manager.KickToSync()
Ricky Liang45c73e72015-01-15 15:00:30 +08001841 except: # pylint: disable=W0702
Justin Chuang83813982013-05-13 01:26:32 +08001842 logging.exception('Unable to check battery or notify shopfloor')
1843 finally:
1844 if message != self.last_check_battery_message:
1845 logging.log(log_level, message)
1846 self.last_check_battery_message = message
1847
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001848 def check_core_dump(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001849 """Checks if there is any core dumped file.
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001850
1851 Removes unwanted core dump files immediately.
1852 Syncs those files matching watch list to server with a delay between
1853 each sync. After the files have been synced to server, deletes the files.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001854 """
Vic Yang6cee2472014-10-22 17:18:52 -07001855 if not self.core_dump_manager:
1856 return
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001857 core_dump_files = self.core_dump_manager.ScanFiles()
1858 if core_dump_files:
1859 now = time.time()
1860 if (self.last_kick_sync_time and now - self.last_kick_sync_time <
1861 self.test_list.options.kick_sync_min_interval_secs):
1862 return
1863 self.last_kick_sync_time = now
1864
1865 # Sends event to server
1866 self.event_log.Log('core_dumped', files=core_dump_files)
1867 self.log_watcher.KickWatchThread()
1868
1869 # Syncs files to server
Cheng-Yi Chianga0f6eff2014-01-09 18:27:22 +08001870 if self.test_list.options.enable_sync_log:
1871 self.system_log_manager.KickToSync(
Cheng-Yi Chiangd3516a32013-07-17 15:30:47 +08001872 core_dump_files, self.core_dump_manager.ClearFiles)
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001873
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001874 def check_log_rotation(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001875 """Checks log rotation file presence/absence according to test_list option.
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001876
1877 Touch /var/lib/cleanup_logs_paused if test_list.options.disable_log_rotation
1878 is True, delete it otherwise. This must be done in idle loop because
1879 autotest client will touch /var/lib/cleanup_logs_paused each time it runs
1880 an autotest.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001881 """
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +08001882 if sys_utils.InChroot():
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001883 return
1884 try:
1885 if self.test_list.options.disable_log_rotation:
1886 open(CLEANUP_LOGS_PAUSED, 'w').close()
1887 else:
1888 file_utils.TryUnlink(CLEANUP_LOGS_PAUSED)
1889 except: # pylint: disable=W0702
1890 # Oh well. Logs an error (but no trace)
1891 logging.info(
1892 'Unable to %s %s: %s',
1893 'touch' if self.test_list.options.disable_log_rotation else 'delete',
Hung-Te Linf707b242016-01-08 23:11:42 +08001894 CLEANUP_LOGS_PAUSED, debug_utils.FormatExceptionOnly())
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001895
Jon Salz8fa8e832012-07-13 19:04:09 +08001896 def sync_time_in_background(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001897 """Writes out current time and tries to sync with shopfloor server."""
Jon Salzb22d1172012-08-06 10:38:57 +08001898 if not self.time_sanitizer:
1899 return
1900
1901 # Write out the current time.
1902 self.time_sanitizer.SaveTime()
1903
Jon Salz54882d02012-08-31 01:57:54 +08001904 if not self._should_sync_time():
Jon Salz8fa8e832012-07-13 19:04:09 +08001905 return
1906
1907 now = time.time()
1908 if self.last_sync_time and (
1909 now - self.last_sync_time <
1910 self.test_list.options.sync_time_period_secs):
1911 # Not yet time for another check.
1912 return
1913 self.last_sync_time = now
1914
1915 def target():
1916 try:
Jon Salz54882d02012-08-31 01:57:54 +08001917 self.sync_time_with_shopfloor_server()
Jon Salz8fa8e832012-07-13 19:04:09 +08001918 except: # pylint: disable=W0702
1919 # Oh well. Log an error (but no trace)
1920 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +08001921 'Unable to get time from shopfloor server: %s',
Hung-Te Linf707b242016-01-08 23:11:42 +08001922 debug_utils.FormatExceptionOnly())
Jon Salz8fa8e832012-07-13 19:04:09 +08001923
1924 thread = threading.Thread(target=target)
1925 thread.daemon = True
1926 thread.start()
1927
Peter Ammon1e1ec572014-06-26 17:56:32 -07001928 def perform_periodic_tasks(self):
1929 """Override of base method to perform periodic work.
Vic Yang4953fc12012-07-26 16:19:53 +08001930
Peter Ammon1e1ec572014-06-26 17:56:32 -07001931 This method must not raise exceptions.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001932 """
Peter Ammon1e1ec572014-06-26 17:56:32 -07001933 super(Goofy, self).perform_periodic_tasks()
Jon Salzb22d1172012-08-06 10:38:57 +08001934
Vic Yang311ddb82012-09-26 12:08:28 +08001935 self.check_exclusive()
cychiang21886742012-07-05 15:16:32 +08001936 self.check_for_updates()
Jon Salz8fa8e832012-07-13 19:04:09 +08001937 self.sync_time_in_background()
Jon Salzb92c5112012-09-21 15:40:11 +08001938 self.log_disk_space_stats()
Justin Chuang83813982013-05-13 01:26:32 +08001939 self.check_battery()
Cheng-Yi Chiangcdfa4182013-05-05 03:20:19 +08001940 self.check_core_dump()
Cheng-Yi Chiang39d32ad2013-07-23 15:02:38 +08001941 self.check_log_rotation()
Jon Salz57717ca2012-04-04 16:47:25 +08001942
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001943 def handle_event_logs(self, chunks, periodic=False):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001944 """Callback for event watcher.
Jon Salz258a40c2012-04-19 12:34:01 +08001945
Jon Salz0697cbf2012-07-04 15:14:04 +08001946 Attempts to upload the event logs to the shopfloor server.
Vic Yang93027612013-05-06 02:42:49 +08001947
1948 Args:
Jon Salzd15bbcf2013-05-21 17:33:57 +08001949 chunks: A list of Chunk objects.
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001950 periodic: This event log handling is periodic. Error messages
1951 will only be shown for the first time.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001952 """
Vic Yang93027612013-05-06 02:42:49 +08001953 first_exception = None
1954 exception_count = 0
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001955 # Suppress error messages for periodic event syncing except for the
1956 # first time. If event syncing is not periodic, always show the error
1957 # messages.
1958 quiet = self._suppress_event_log_error_messages if periodic else False
Vic Yang93027612013-05-06 02:42:49 +08001959
Jon Salzd15bbcf2013-05-21 17:33:57 +08001960 for chunk in chunks:
Vic Yang93027612013-05-06 02:42:49 +08001961 try:
Jon Salzcddb6402013-05-23 12:56:42 +08001962 description = 'event logs (%s)' % str(chunk)
Vic Yang93027612013-05-06 02:42:49 +08001963 start_time = time.time()
1964 shopfloor_client = shopfloor.get_instance(
Ricky Liang45c73e72015-01-15 15:00:30 +08001965 detect=True,
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001966 timeout=self.test_list.options.shopfloor_timeout_secs,
1967 quiet=quiet)
Ricky Liang45c73e72015-01-15 15:00:30 +08001968 shopfloor_client.UploadEvent(chunk.log_name + '.' +
Jon Salzd15bbcf2013-05-21 17:33:57 +08001969 event_log.GetReimageId(),
1970 Binary(chunk.chunk))
Vic Yang93027612013-05-06 02:42:49 +08001971 logging.info(
Ricky Liang45c73e72015-01-15 15:00:30 +08001972 'Successfully synced %s in %.03f s',
1973 description, time.time() - start_time)
1974 except: # pylint: disable=W0702
Hung-Te Linf707b242016-01-08 23:11:42 +08001975 first_exception = (first_exception or
1976 (chunk.log_name + ': ' +
1977 debug_utils.FormatExceptionOnly()))
Vic Yang93027612013-05-06 02:42:49 +08001978 exception_count += 1
1979
1980 if exception_count:
1981 if exception_count == 1:
1982 msg = 'Log upload failed: %s' % first_exception
1983 else:
1984 msg = '%d log upload failed; first is: %s' % (
1985 exception_count, first_exception)
Cheng-Yi Chiangf5b21012015-03-17 15:37:14 +08001986 # For periodic event log syncing, only show the first error messages.
1987 if periodic:
1988 if not self._suppress_event_log_error_messages:
1989 self._suppress_event_log_error_messages = True
1990 logging.warning('Suppress periodic shopfloor error messages for '
1991 'event log syncing after the first one.')
1992 raise Exception(msg)
1993 # For event log syncing by request, show the error messages.
1994 else:
1995 raise Exception(msg)
Vic Yang93027612013-05-06 02:42:49 +08001996
Ricky Liang45c73e72015-01-15 15:00:30 +08001997 def run_tests_with_status(self, statuses_to_run, starting_at=None, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08001998 """Runs all top-level tests with a particular status.
Jon Salz0405ab52012-03-16 15:26:52 +08001999
Jon Salz0697cbf2012-07-04 15:14:04 +08002000 All active tests, plus any tests to re-run, are reset.
Jon Salz57717ca2012-04-04 16:47:25 +08002001
Jon Salz0697cbf2012-07-04 15:14:04 +08002002 Args:
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002003 statuses_to_run: The particular status that caller wants to run.
Jon Salz0697cbf2012-07-04 15:14:04 +08002004 starting_at: If provided, only auto-runs tests beginning with
2005 this test.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002006 root: The root of tests to run. If not provided, it will be
2007 the root of all tests.
2008 """
Jon Salz0697cbf2012-07-04 15:14:04 +08002009 root = root or self.test_list
Jon Salz57717ca2012-04-04 16:47:25 +08002010
Jon Salz0697cbf2012-07-04 15:14:04 +08002011 if starting_at:
2012 # Make sure they passed a test, not a string.
2013 assert isinstance(starting_at, factory.FactoryTest)
Jon Salz0405ab52012-03-16 15:26:52 +08002014
Jon Salz0697cbf2012-07-04 15:14:04 +08002015 tests_to_reset = []
2016 tests_to_run = []
Jon Salz0405ab52012-03-16 15:26:52 +08002017
Jon Salz0697cbf2012-07-04 15:14:04 +08002018 found_starting_at = False
Jon Salz0405ab52012-03-16 15:26:52 +08002019
Jon Salz0697cbf2012-07-04 15:14:04 +08002020 for test in root.get_top_level_tests():
2021 if starting_at:
2022 if test == starting_at:
2023 # We've found starting_at; do auto-run on all
2024 # subsequent tests.
2025 found_starting_at = True
2026 if not found_starting_at:
2027 # Don't start this guy yet
2028 continue
Jon Salz0405ab52012-03-16 15:26:52 +08002029
Jon Salz0697cbf2012-07-04 15:14:04 +08002030 status = test.get_state().status
2031 if status == TestState.ACTIVE or status in statuses_to_run:
2032 # Reset the test (later; we will need to abort
2033 # all active tests first).
2034 tests_to_reset.append(test)
2035 if status in statuses_to_run:
2036 tests_to_run.append(test)
Jon Salz0405ab52012-03-16 15:26:52 +08002037
Jon Salz6dc031d2013-06-19 13:06:23 +08002038 self.abort_active_tests('Operator requested run/re-run of certain tests')
Jon Salz258a40c2012-04-19 12:34:01 +08002039
Jon Salz0697cbf2012-07-04 15:14:04 +08002040 # Reset all statuses of the tests to run (in case any tests were active;
2041 # we want them to be run again).
2042 for test_to_reset in tests_to_reset:
2043 for test in test_to_reset.walk():
2044 test.update_state(status=TestState.UNTESTED)
Jon Salz57717ca2012-04-04 16:47:25 +08002045
Chih-Yu Huang85dc63c2015-08-12 15:21:28 +08002046 self.run_tests(tests_to_run, [TestState.UNTESTED])
Jon Salz0405ab52012-03-16 15:26:52 +08002047
Jon Salz0697cbf2012-07-04 15:14:04 +08002048 def restart_tests(self, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002049 """Restarts all tests."""
Jon Salz0697cbf2012-07-04 15:14:04 +08002050 root = root or self.test_list
Jon Salz0405ab52012-03-16 15:26:52 +08002051
Jon Salz6dc031d2013-06-19 13:06:23 +08002052 self.abort_active_tests('Operator requested restart of certain tests')
Jon Salz0697cbf2012-07-04 15:14:04 +08002053 for test in root.walk():
Ricky Liangfea4ac92014-08-21 11:55:59 +08002054 test.update_state(status=TestState.UNTESTED)
Jon Salz0697cbf2012-07-04 15:14:04 +08002055 self.run_tests(root)
Hung-Te Lin96632362012-03-20 21:14:18 +08002056
Jon Salz0697cbf2012-07-04 15:14:04 +08002057 def auto_run(self, starting_at=None, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002058 """"Auto-runs" tests that have not been run yet.
Hung-Te Lin96632362012-03-20 21:14:18 +08002059
Jon Salz0697cbf2012-07-04 15:14:04 +08002060 Args:
2061 starting_at: If provide, only auto-runs tests beginning with
2062 this test.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002063 root: If provided, the root of tests to run. If not provided, the root
2064 will be test_list (root of all tests).
2065 """
Jon Salz0697cbf2012-07-04 15:14:04 +08002066 root = root or self.test_list
2067 self.run_tests_with_status([TestState.UNTESTED, TestState.ACTIVE],
Ricky Liang45c73e72015-01-15 15:00:30 +08002068 starting_at=starting_at,
2069 root=root)
Jon Salz968e90b2012-03-18 16:12:43 +08002070
Jon Salz0697cbf2012-07-04 15:14:04 +08002071 def re_run_failed(self, root=None):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002072 """Re-runs failed tests."""
Jon Salz0697cbf2012-07-04 15:14:04 +08002073 root = root or self.test_list
2074 self.run_tests_with_status([TestState.FAILED], root=root)
Jon Salz57717ca2012-04-04 16:47:25 +08002075
Jon Salz0697cbf2012-07-04 15:14:04 +08002076 def show_review_information(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002077 """Event handler for showing review information screen.
Jon Salz57717ca2012-04-04 16:47:25 +08002078
Peter Ammon1e1ec572014-06-26 17:56:32 -07002079 The information screen is rendered by main UI program (ui.py), so in
Jon Salz0697cbf2012-07-04 15:14:04 +08002080 goofy we only need to kill all active tests, set them as untested, and
2081 clear remaining tests.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002082 """
Jon Salz0697cbf2012-07-04 15:14:04 +08002083 self.kill_active_tests(False)
Jon Salza6711d72012-07-18 14:33:03 +08002084 self.cancel_pending_tests()
Jon Salz57717ca2012-04-04 16:47:25 +08002085
Jon Salz0697cbf2012-07-04 15:14:04 +08002086 def handle_switch_test(self, event):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002087 """Switches to a particular test.
Jon Salz0405ab52012-03-16 15:26:52 +08002088
Ricky Liang6fe218c2013-12-27 15:17:17 +08002089 Args:
2090 event: The SWITCH_TEST event.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002091 """
Jon Salz0697cbf2012-07-04 15:14:04 +08002092 test = self.test_list.lookup_path(event.path)
2093 if not test:
2094 logging.error('Unknown test %r', event.key)
2095 return
Jon Salz73e0fd02012-04-04 11:46:38 +08002096
Jon Salz0697cbf2012-07-04 15:14:04 +08002097 invoc = self.invocations.get(test)
2098 if invoc and test.backgroundable:
2099 # Already running: just bring to the front if it
2100 # has a UI.
2101 logging.info('Setting visible test to %s', test.path)
Jon Salz36fbbb52012-07-05 13:45:06 +08002102 self.set_visible_test(test)
Jon Salz0697cbf2012-07-04 15:14:04 +08002103 return
Jon Salz73e0fd02012-04-04 11:46:38 +08002104
Jon Salz6dc031d2013-06-19 13:06:23 +08002105 self.abort_active_tests('Operator requested abort (switch_test)')
Jon Salz0697cbf2012-07-04 15:14:04 +08002106 for t in test.walk():
2107 t.update_state(status=TestState.UNTESTED)
Jon Salz73e0fd02012-04-04 11:46:38 +08002108
Jon Salz0697cbf2012-07-04 15:14:04 +08002109 if self.test_list.options.auto_run_on_keypress:
2110 self.auto_run(starting_at=test)
2111 else:
2112 self.run_tests(test)
Jon Salz73e0fd02012-04-04 11:46:38 +08002113
Wei-Ning Huang38b75f02015-02-25 18:25:14 +08002114 def handle_key_filter_mode(self, event):
2115 if self.key_filter:
2116 if getattr(event, 'enabled'):
2117 self.key_filter.Start()
2118 else:
2119 self.key_filter.Stop()
2120
Jon Salz0697cbf2012-07-04 15:14:04 +08002121 def wait(self):
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002122 """Waits for all pending invocations.
Jon Salz0697cbf2012-07-04 15:14:04 +08002123
2124 Useful for testing.
Cheng-Yi Chiang1e3e2692013-12-24 18:02:36 +08002125 """
Jon Salz1acc8742012-07-17 17:45:55 +08002126 while self.invocations:
2127 for k, v in self.invocations.iteritems():
2128 logging.info('Waiting for %s to complete...', k)
2129 v.thread.join()
2130 self.reap_completed_tests()
Jon Salz0697cbf2012-07-04 15:14:04 +08002131
Claire Changd1961a22015-08-05 16:15:55 +08002132 def test_fail(self, test):
Hung-Te Lin410f70a2015-12-15 14:53:42 +08002133 self.dut.hooks.OnTestFailure(test)
Claire Changd1961a22015-08-05 16:15:55 +08002134 if self.link_manager:
2135 self.link_manager.UpdateStatus(False)
2136
Hung-Te Linf2f78f72012-02-08 19:27:11 +08002137if __name__ == '__main__':
Peter Ammona3d298c2014-09-23 10:11:02 -07002138 Goofy.run_main_and_exit()