autoupdate_EndToEndTest.py revision fea7e766e59f8356dad6f70e46c0ee25997863a5
10ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 20ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold# Use of this source code is governed by a BSD-style license that can be 30ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold# found in the LICENSE file. 40ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 52f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosaimport collections 60ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldimport json 70ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldimport logging 86c55bdb98e967675456a71a0971b81058536cac8Chris Sosaimport os 9a0261611f9be78ee9d456fd50bea81e9eda07c17Gilad Arnoldimport socket 1015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnoldimport time 110ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldimport urllib2 120ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldimport urlparse 1303901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold 146c55bdb98e967675456a71a0971b81058536cac8Chris Sosafrom autotest_lib.client.bin import utils as client_utils 156c55bdb98e967675456a71a0971b81058536cac8Chris Sosafrom autotest_lib.client.common_lib import error, global_config 160ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldfrom autotest_lib.client.common_lib.cros import autoupdater, dev_server 17d874a4d63dacfb6e8a74466eab5160e940aaa690Dan Shifrom autotest_lib.client.common_lib.cros.graphite import autotest_stats 188ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basifrom autotest_lib.server import autotest, hosts, test 192f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosafrom autotest_lib.server.cros.dynamic_suite import tools 200ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 210ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 220ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnolddef _wait(secs, desc=None): 230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Emits a log message and sleeps for a given number of seconds.""" 240338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold msg = 'Waiting %s seconds' % secs 250ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if desc: 260ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold msg += ' (%s)' % desc 270ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold logging.info(msg) 280ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold time.sleep(secs) 290ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 300ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 31ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosaclass ExpectedUpdateEventChainFailed(error.TestFail): 32ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Raised if we fail to receive an expected event in a chain.""" 33ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 34f789cf3a52c720344062f0a6c782bb758f08b189Don Garrettclass RequiredArgumentMissing(error.TestFail): 35f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett """Raised if we fail to receive an expected event in a chain.""" 36f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 37ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 380338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold# Update event types. 390338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_DOWNLOAD_COMPLETE = '1' 400338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_INSTALL_COMPLETE = '2' 410338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_UPDATE_COMPLETE = '3' 420338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_DOWNLOAD_STARTED = '13' 430338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_DOWNLOAD_FINISHED = '14' 440338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 450338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold# Update event results. 460338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_ERROR = '0' 470338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_SUCCESS = '1' 480338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_SUCCESS_REBOOT = '2' 490338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_UPDATE_DEFERRED = '9' 500338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 510338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 520ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass ExpectedUpdateEvent(object): 53ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Defines an expected event in a host update process. 54ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 55ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa Attrs: 56ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa _expected_attrs: Dictionary of attributes that should match events 57ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa received. If attribute is not provided, assumes match. 58ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa error_message: What we should error out with if we fail to verify this 59ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa expected event. 60ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """ 6145f02ae47134953169805d281992c9edf0019250Chris Sosa 6245f02ae47134953169805d281992c9edf0019250Chris Sosa # Omaha event types/results, from update_engine/omaha_request_action.h 6345f02ae47134953169805d281992c9edf0019250Chris Sosa # These are stored in dict form in order to easily print out the keys. 640338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold _EVENT_TYPE_DICT = { 650338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_TYPE_DOWNLOAD_COMPLETE: 'download_complete', 660338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_TYPE_INSTALL_COMPLETE: 'install_complete', 670338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_TYPE_UPDATE_COMPLETE: 'update_complete', 680338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_TYPE_DOWNLOAD_STARTED: 'download_started', 690338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_TYPE_DOWNLOAD_FINISHED: 'download_finished' 700338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold } 710338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 720338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold _EVENT_RESULT_DICT = { 730338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_RESULT_ERROR: 'error', 740338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_RESULT_SUCCESS: 'success', 750338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_RESULT_SUCCESS_REBOOT: 'success_reboot', 760338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_RESULT_UPDATE_DEFERRED: 'update_deferred' 770338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold } 780338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 790338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold _ATTR_NAME_DICT_MAP = { 800338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'event_type': _EVENT_TYPE_DICT, 810338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'event_result': _EVENT_RESULT_DICT, 820338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold } 830338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 840338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold _VALID_TYPES = set(_EVENT_TYPE_DICT.keys()) 850338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold _VALID_RESULTS = set(_EVENT_RESULT_DICT.keys()) 8645f02ae47134953169805d281992c9edf0019250Chris Sosa 870ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __init__(self, event_type=None, event_result=None, version=None, 88ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa previous_version=None, error_message=None): 890338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if event_type and event_type not in self._VALID_TYPES: 9045f02ae47134953169805d281992c9edf0019250Chris Sosa raise ValueError('event_type %s is not valid.' % event_type) 9145f02ae47134953169805d281992c9edf0019250Chris Sosa 920338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if event_result and event_result not in self._VALID_RESULTS: 9345f02ae47134953169805d281992c9edf0019250Chris Sosa raise ValueError('event_result %s is not valid.' % event_result) 9445f02ae47134953169805d281992c9edf0019250Chris Sosa 950ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._expected_attrs = { 960ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'event_type': event_type, 970ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'event_result': event_result, 980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'version': version, 990ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'previous_version': previous_version, 1000ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold } 101ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self.error_message = error_message 1020ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1030ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1040338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold @staticmethod 1050338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold def _attr_val_str(attr_val, helper_dict, default=None): 1060338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """Returns an enriched attribute value string, or default.""" 1070338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if not attr_val: 1080338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return default 1090338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1100338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold s = str(attr_val) 1110338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if helper_dict: 1120338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold s += ':%s' % helper_dict.get(attr_val, 'unknown') 1130338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1140338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return s 1150338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1160338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1170338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold def _attr_name_and_values(self, attr_name, expected_attr_val, 1180338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual_attr_val=None): 1190338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """Returns an attribute name, expected and actual value strings. 1200338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1210338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold This will return (name, expected, actual); the returned value for 1220338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual will be None if its respective input is None/empty. 1230338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1240338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """ 1250338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold helper_dict = self._ATTR_NAME_DICT_MAP.get(attr_name) 1260338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold expected_attr_val_str = self._attr_val_str(expected_attr_val, 1270338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold helper_dict, 1280338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold default='any') 1290338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual_attr_val_str = self._attr_val_str(actual_attr_val, helper_dict) 1300338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1310338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return attr_name, expected_attr_val_str, actual_attr_val_str 1320338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1330338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1340ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __str__(self): 1350338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return ' '.join(['%s=%s' % 1360338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold self._attr_name_and_values(attr_name, attr_val)[0:2] 1370ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold for attr_name, attr_val 1380ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold in self._expected_attrs.iteritems()]) 1390ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1400ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1410ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def verify(self, actual_event): 1420ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verify the attributes of an actual event. 1430ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 144ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa @param actual_event: a dictionary containing event attributes 1450ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1460ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return True if all attributes as expected, False otherwise. 1470ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1480ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 1490ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return all([self._verify_attr(attr_name, expected_attr_val, 1500ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold actual_event.get(attr_name)) 1510ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold for attr_name, expected_attr_val 1520ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold in self._expected_attrs.iteritems() if expected_attr_val]) 1530ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1540ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1550ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def _verify_attr(self, attr_name, expected_attr_val, actual_attr_val): 1560ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies that an actual log event attributes matches expected on. 1570ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param attr_name: name of the attribute to verify 1590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param expected_attr_val: expected attribute value 1600ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param actual_attr_val: actual attribute value 1610ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1620ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return True if actual value is present and matches, False otherwise. 1630ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 16545f02ae47134953169805d281992c9edf0019250Chris Sosa # None values are assumed to be missing and non-matching. 16645f02ae47134953169805d281992c9edf0019250Chris Sosa if not actual_attr_val: 1670338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.error('No value found for %s (expected %s)', 1680338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold *self._attr_name_and_values(attr_name, 1690338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold expected_attr_val)[0:2]) 17045f02ae47134953169805d281992c9edf0019250Chris Sosa return False 17145f02ae47134953169805d281992c9edf0019250Chris Sosa 1720338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold # Convert actual value to a string. 17345f02ae47134953169805d281992c9edf0019250Chris Sosa actual_attr_val = str(actual_attr_val) 17445f02ae47134953169805d281992c9edf0019250Chris Sosa 17545f02ae47134953169805d281992c9edf0019250Chris Sosa if not actual_attr_val == expected_attr_val: 1760338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold # We allow expected version numbers (e.g. 2940.0.0) to be contained 1770338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold # in actual values (2940.0.0-a1); this is necessary for the test to 1780338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold # pass with developer / non-release images. 1790338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if 'version' in attr_name and expected_attr_val in actual_attr_val: 1800338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Expected %s (%s) contained in actual value (%s) ' 1810338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'but does not match exactly', 1820338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold *self._attr_name_and_values( 1830338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold attr_name, expected_attr_val, 1840338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual_attr_val=actual_attr_val)) 185fec1349a3e70eb41dce8bc07a8c63563d23d64b2Chris Sosa return True 186fec1349a3e70eb41dce8bc07a8c63563d23d64b2Chris Sosa 1870338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.error('Expected %s (%s) different from actual value (%s)', 1880338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold *self._attr_name_and_values( 1890338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold attr_name, expected_attr_val, 1900338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual_attr_val=actual_attr_val)) 1910ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return False 1920ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1930ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return True 1940ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1950ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1960ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass ExpectedUpdateEventChain(object): 1970ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Defines a chain of expected update events.""" 1980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __init__(self, *expected_event_chain_args): 1990ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Initialize the chain object. 2000ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2010ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param expected_event_chain_args: list of tuples arguments, each 2020ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold containing a timeout (in seconds) and an ExpectedUpdateEvent 2030ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold object. 2040ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2050ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 2060ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._expected_event_chain = expected_event_chain_args 2070ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2080ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 209cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @staticmethod 210cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold def _format_event_with_timeout(timeout, expected_event): 211cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Returns a string representation of the event, with timeout.""" 2120ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return ('%s %s' % 2130ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold (expected_event, 2140ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold ('within %s seconds' % timeout) if timeout 2150ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold else 'indefinitely')) 2160ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2170ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2180ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __str__(self): 2190ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return ('[%s]' % 2200ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold ', '.join( 2210ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold [self._format_event_with_timeout(timeout, expected_event) 2220ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold for timeout, expected_event 2230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold in self._expected_event_chain])) 2240ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2250ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2260ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __repr__(self): 2270ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return str(self._expected_event_chain) 2280ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2290ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2300ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def verify(self, get_next_event): 2310ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies that an actual stream of events complies. 2320ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2330ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param get_next_event: a function returning the next event 2340ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 235ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify an event. 2360ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2370ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 2380ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold for timeout, expected_event in self._expected_event_chain: 2390338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Expecting %s', 240ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._format_event_with_timeout(timeout, 241ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa expected_event)) 2420ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if not self._verify_event_with_timeout( 2430ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold timeout, expected_event, get_next_event): 244ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa logging.error('Failed expected event: %s', 245ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa expected_event.error_message) 246ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa raise ExpectedUpdateEventChainFailed( 247ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa expected_event.error_message) 2480ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2490ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 250cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @staticmethod 251cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold def _verify_event_with_timeout(timeout, expected_event, get_next_event): 2520ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verify an expected event occurs within a given timeout. 2530ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2540ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param timeout: specified in seconds 2550ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param expected_event: an expected event specification 2560ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param get_next_event: function returning the next event in a stream 2570ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return True if event complies, False otherwise. 2590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2600ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 2610ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold base_timestamp = curr_timestamp = time.time() 2620ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold expired_timestamp = base_timestamp + timeout 2630ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold while curr_timestamp <= expired_timestamp: 2640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold new_event = get_next_event() 2650ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if new_event: 2660338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Event received after %s seconds', 2670338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold round(curr_timestamp - base_timestamp, 1)) 2680ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return expected_event.verify(new_event) 2690ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2700ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # No new events, sleep for one second only (so we don't miss 2710ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # events at the end of the allotted timeout). 2720ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold time.sleep(1) 2730ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold curr_timestamp = time.time() 2740ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2750338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.error('Timeout expired') 2760ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return False 2770ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2780ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2790ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass UpdateEventLogVerifier(object): 2800ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies update event chains on a devserver update log.""" 28103901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold def __init__(self, event_log_url, url_request_timeout=None): 2820ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._event_log_url = event_log_url 28303901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold self._url_request_timeout = url_request_timeout 2840ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._event_log = [] 2850ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._num_consumed_events = 0 2860ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2870ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2880ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def verify_expected_event_chain(self, expected_event_chain): 289ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa """Verify a given event chain. 290ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa 291ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa @param expected_event_chain: instance of expected event chain. 292ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 293ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify the an 294ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa event. 295ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa """ 296ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa expected_event_chain.verify(self._get_next_log_event) 2970ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2990ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def _get_next_log_event(self): 3000ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Returns the next event in an event log. 3010ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3020ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold Uses the URL handed to it during initialization to obtain the host log 3030ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold from a devserver. If new events are encountered, the first of them is 3040ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold consumed and returned. 3050ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3060ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return The next new event in the host log, as reported by devserver; 30703901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold None if no such event was found or an error occurred. 3080ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3090ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 3100ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # (Re)read event log from devserver, if necessary. 3110ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if len(self._event_log) <= self._num_consumed_events: 31203901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold try: 31303901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold if self._url_request_timeout: 31403901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold conn = urllib2.urlopen(self._event_log_url, 31503901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold timeout=self._url_request_timeout) 31603901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold else: 31703901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold conn = urllib2.urlopen(self._event_log_url) 31803901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold except urllib2.URLError, e: 3190338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.warning('Failed to read event log url: %s', e) 32003901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold return None 321a0261611f9be78ee9d456fd50bea81e9eda07c17Gilad Arnold except socket.timeout, e: 322a0261611f9be78ee9d456fd50bea81e9eda07c17Gilad Arnold logging.warning('Timed out reading event log url: %s', e) 323a0261611f9be78ee9d456fd50bea81e9eda07c17Gilad Arnold return None 32403901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold 3250ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold event_log_resp = conn.read() 3260ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold conn.close() 3270ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._event_log = json.loads(event_log_resp) 3280ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 32903901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold # Return next new event, if one is found. 3300ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if len(self._event_log) > self._num_consumed_events: 3310ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold new_event = self._event_log[self._num_consumed_events] 3320ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._num_consumed_events += 1 3330338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Consumed new event: %s', new_event) 3340ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return new_event 3350ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3360ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 337793344b359304c31d78197788b55cfbbe2636025Chris Sosaclass OmahaDevserverFailedToStart(error.TestError): 338793344b359304c31d78197788b55cfbbe2636025Chris Sosa """Raised when a omaha devserver fails to start.""" 339793344b359304c31d78197788b55cfbbe2636025Chris Sosa 340793344b359304c31d78197788b55cfbbe2636025Chris Sosa 3410ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass OmahaDevserver(object): 3420ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Spawns a test-private devserver instance.""" 343793344b359304c31d78197788b55cfbbe2636025Chris Sosa # How long to wait for a devserver to start. 34452c35724507ec105053d2af792fe161a627e05c1Alex Deymo _WAIT_FOR_DEVSERVER_STARTED_SECONDS = 30 345793344b359304c31d78197788b55cfbbe2636025Chris Sosa 346260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # How long to sleep (seconds) between checks to see if a devserver is up. 34703901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold _WAIT_SLEEP_INTERVAL = 1 3480ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3496f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # Max devserver execution time (seconds); used with timeout(1) to ensure we 3506f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # don't have defunct instances hogging the system. 3516f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold _DEVSERVER_TIMELIMIT_SECONDS = 12 * 60 * 60 352793344b359304c31d78197788b55cfbbe2636025Chris Sosa 353793344b359304c31d78197788b55cfbbe2636025Chris Sosa 354260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def __init__(self, omaha_host, devserver_dir, update_payload_staged_url): 3550ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Starts a private devserver instance, operating at Omaha capacity. 3560ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3570ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param omaha_host: host address where the devserver is spawned. 35803901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold @param devserver_dir: path to the devserver source directory 359ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param update_payload_staged_url: URL to provision for update requests. 3600ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3610ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 362ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa if not update_payload_staged_url: 3630338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold raise error.TestError('Missing update payload url') 3640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3656c55bdb98e967675456a71a0971b81058536cac8Chris Sosa self._omaha_host = omaha_host 366260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid = 0 367260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_port = 0 # Determined later from devserver portfile. 3686c55bdb98e967675456a71a0971b81058536cac8Chris Sosa self._devserver_dir = devserver_dir 369ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._update_payload_staged_url = update_payload_staged_url 3706c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 3716c55bdb98e967675456a71a0971b81058536cac8Chris Sosa self._devserver_ssh = hosts.SSHHost(self._omaha_host, 3726c55bdb98e967675456a71a0971b81058536cac8Chris Sosa user=os.environ['USER']) 373260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 3743563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa # Temporary files for various devserver outputs. 3753563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_logfile = None 376238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo self._devserver_stdoutfile = None 3773563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_portfile = None 3783563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_pidfile = None 3793563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_static_dir = None 3803563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 3813563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 3823563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa def _cleanup_devserver_files(self): 3833563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa """Cleans up the temporary devserver files.""" 384238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo for filename in (self._devserver_logfile, self._devserver_stdoutfile, 385238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo self._devserver_portfile, self._devserver_pidfile): 386238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo if filename: 387238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo self._devserver_ssh.run('rm -f %s' % filename, 388238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo ignore_status=True) 3893563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 3903563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa if self._devserver_static_dir: 3913563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_ssh.run('rm -rf %s' % self._devserver_static_dir, 3923563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa ignore_status=True) 3933563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 394260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 3953563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa def _create_tempfile_on_devserver(self, label, dir=False): 3963563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa """Creates a temporary file/dir on the devserver and returns its path. 397260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 398260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @param label: Identifier for the file context (string, no whitespaces). 3993563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa @param dir: If True, create a directory instead of a file. 400260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 401260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @raises test.TestError: If we failed to invoke mktemp on the server. 402260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @raises OmahaDevserverFailedToStart: If tempfile creation failed. 403260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """ 404260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold remote_cmd = 'mktemp --tmpdir devserver-%s.XXXXXX' % label 4053563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa if dir: 4063563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa remote_cmd += ' --directory' 4073563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 408260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 409260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold result = self._devserver_ssh.run(remote_cmd, ignore_status=True) 410260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except error.AutoservRunError as e: 411260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._log_and_raise_remote_ssh_error(e) 412260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if result.exit_status != 0: 413260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold raise OmahaDevserverFailedToStart( 414260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'Could not create a temporary %s file on the devserver, ' 415a7412a90ffefac2b6314726b284af1b31d6bd797Alex Deymo 'error output: "%s"' % (label, result.stderr)) 416260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return result.stdout.strip() 417260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 418260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @staticmethod 419260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _log_and_raise_remote_ssh_error(e): 420260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Logs failure to ssh remote, then raises a TestError.""" 421260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.debug('Failed to ssh into the devserver: %s', e) 422260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.error('If you are running this locally it means you did not ' 423260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'configure ssh correctly.') 424260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold raise error.TestError('Failed to ssh into the devserver: %s' % e) 425260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 426260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 427260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _read_int_from_devserver_file(self, filename): 428260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Reads and returns an integer value from a file on the devserver.""" 429260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return int(self._get_devserver_file_content(filename).strip()) 4300ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 4316c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 432793344b359304c31d78197788b55cfbbe2636025Chris Sosa def _wait_for_devserver_to_start(self): 433793344b359304c31d78197788b55cfbbe2636025Chris Sosa """Waits until the devserver starts within the time limit. 434793344b359304c31d78197788b55cfbbe2636025Chris Sosa 435260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold Infers and sets the devserver PID and serving port. 436260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 437793344b359304c31d78197788b55cfbbe2636025Chris Sosa Raises: 438793344b359304c31d78197788b55cfbbe2636025Chris Sosa OmahaDevserverFailedToStart: If the time limit is reached and we 439793344b359304c31d78197788b55cfbbe2636025Chris Sosa cannot connect to the devserver. 440793344b359304c31d78197788b55cfbbe2636025Chris Sosa """ 441260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # Compute the overall timeout. 442260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold deadline = time.time() + self._WAIT_FOR_DEVSERVER_STARTED_SECONDS 443260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 444260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # First, wait for port file to be filled and determine the server port. 44594b9ad4983cc735e162a3549c1628d08241b0d57Gilad Arnold logging.warning('Waiting for devserver to start up.') 446260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold while time.time() < deadline: 447260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 448260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid = self._read_int_from_devserver_file( 449260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pidfile) 450260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_port = self._read_int_from_devserver_file( 451260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_portfile) 452260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.info('Devserver pid is %d, serving on port %d', 453260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid, self._devserver_port) 454260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold break 455260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except Exception: # Couldn't read file or corrupt content. 456260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold time.sleep(self._WAIT_SLEEP_INTERVAL) 457260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold else: 45852c35724507ec105053d2af792fe161a627e05c1Alex Deymo try: 45952c35724507ec105053d2af792fe161a627e05c1Alex Deymo self._devserver_ssh.run_output('uptime') 46052c35724507ec105053d2af792fe161a627e05c1Alex Deymo except error.AutoservRunError as e: 46152c35724507ec105053d2af792fe161a627e05c1Alex Deymo logging.debug('Failed to run uptime on the devserver: %s', e) 46294b9ad4983cc735e162a3549c1628d08241b0d57Gilad Arnold raise OmahaDevserverFailedToStart( 463260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'The test failed to find the pid/port of the omaha ' 46452c35724507ec105053d2af792fe161a627e05c1Alex Deymo 'devserver after %d seconds. Check the dumped devserver ' 46552c35724507ec105053d2af792fe161a627e05c1Alex Deymo 'logs and devserver load for more information.' % 46652c35724507ec105053d2af792fe161a627e05c1Alex Deymo self._WAIT_FOR_DEVSERVER_STARTED_SECONDS) 467260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 468260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # Check that the server is reponsding to network requests. 469260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.warning('Waiting for devserver to accept network requests.') 470260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold url = 'http://%s' % self.get_netloc() 471260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold while time.time() < deadline: 472260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if dev_server.DevServer.devserver_healthy(url, timeout_min=0.1): 473260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold break 474793344b359304c31d78197788b55cfbbe2636025Chris Sosa 475793344b359304c31d78197788b55cfbbe2636025Chris Sosa # TODO(milleral): Refactor once crbug.com/221626 is resolved. 476793344b359304c31d78197788b55cfbbe2636025Chris Sosa time.sleep(self._WAIT_SLEEP_INTERVAL) 477793344b359304c31d78197788b55cfbbe2636025Chris Sosa else: 478793344b359304c31d78197788b55cfbbe2636025Chris Sosa raise OmahaDevserverFailedToStart( 479793344b359304c31d78197788b55cfbbe2636025Chris Sosa 'The test failed to establish a connection to the omaha ' 480793344b359304c31d78197788b55cfbbe2636025Chris Sosa 'devserver it set up on port %d. Check the dumped ' 481260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'devserver logs for more information.' % 482260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_port) 483793344b359304c31d78197788b55cfbbe2636025Chris Sosa 484793344b359304c31d78197788b55cfbbe2636025Chris Sosa 4856c55bdb98e967675456a71a0971b81058536cac8Chris Sosa def start_devserver(self): 486793344b359304c31d78197788b55cfbbe2636025Chris Sosa """Starts the devserver and confirms it is up. 487793344b359304c31d78197788b55cfbbe2636025Chris Sosa 488793344b359304c31d78197788b55cfbbe2636025Chris Sosa Raises: 489260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold test.TestError: If we failed to spawn the remote devserver. 490793344b359304c31d78197788b55cfbbe2636025Chris Sosa OmahaDevserverFailedToStart: If the time limit is reached and we 491793344b359304c31d78197788b55cfbbe2636025Chris Sosa cannot connect to the devserver. 4926c55bdb98e967675456a71a0971b81058536cac8Chris Sosa """ 4932f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa update_payload_url_base, update_payload_path = self._split_url( 494ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._update_payload_staged_url) 4953563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 4963563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa # Allocate temporary files for various server outputs. 4973563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_logfile = self._create_tempfile_on_devserver('log') 498238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo self._devserver_stdoutfile = self._create_tempfile_on_devserver( 499238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo 'stdout') 5003563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_portfile = self._create_tempfile_on_devserver('port') 5013563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_pidfile = self._create_tempfile_on_devserver('pid') 5023563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_static_dir = self._create_tempfile_on_devserver( 5033563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 'static', dir=True) 5043563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 5056f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # Invoke the Omaha/devserver on the remote server. Will attempt to kill 5066f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # it with a SIGTERM after a predetermined timeout has elapsed, followed 5076f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # by SIGKILL if not dead within 30 seconds from the former signal. 5080ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold cmdlist = [ 5096f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold 'timeout', '-s', 'TERM', '-k', '30', 5106f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold str(self._DEVSERVER_TIMELIMIT_SECONDS), 5116c55bdb98e967675456a71a0971b81058536cac8Chris Sosa '%s/devserver.py' % self._devserver_dir, 5120ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--payload=%s' % update_payload_path, 513260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--port=0', 514260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--pidfile=%s' % self._devserver_pidfile, 515260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--portfile=%s' % self._devserver_portfile, 516260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--logfile=%s' % self._devserver_logfile, 5170ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--remote_payload', 5180ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--urlbase=%s' % update_payload_url_base, 5190ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--max_updates=1', 5200ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--host_log', 5213563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa '--static_dir=%s' % self._devserver_static_dir, 5220ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold ] 523238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo remote_cmd = '( %s ) </dev/null >%s 2>&1 &' % ( 524238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo ' '.join(cmdlist), self._devserver_stdoutfile) 5256c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 526260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.info('Starting devserver with %r', remote_cmd) 527260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 528260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_ssh.run_output(remote_cmd) 529260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except error.AutoservRunError as e: 530260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._log_and_raise_remote_ssh_error(e) 5316c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 532260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 533260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._wait_for_devserver_to_start() 534260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except OmahaDevserverFailedToStart: 535260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._kill_remote_process() 536260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._dump_devserver_log() 537299e7788f7054dccab196dd7274f75ad41b66606Alex Deymo self._cleanup_devserver_files() 538260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold raise 53938ba6b79b19b5bdd9cfe71b26efd0c267768527aGilad Arnold 5406c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 541260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _kill_remote_process(self): 542260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Kills the devserver and verifies it's down; clears the remote pid.""" 543260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def devserver_down(): 544cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Ensure that the devserver process is down.""" 545260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return not self._remote_process_alive() 5466c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 547260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if devserver_down(): 5486c55bdb98e967675456a71a0971b81058536cac8Chris Sosa return 5496c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 550260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold for signal in 'SIGTERM', 'SIGKILL': 551260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold remote_cmd = 'kill -s %s %s' % (signal, self._devserver_pid) 552260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_ssh.run(remote_cmd) 553260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 554260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold client_utils.poll_for_condition( 555260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold devserver_down, sleep_interval=1, desc='devserver down') 556260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold break 557260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except client_utils.TimeoutError: 558260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.warning('Could not kill devserver with %s.', signal) 559260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold else: 560260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.warning('Failed to kill devserver, giving up.') 561260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 562260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid = None 5636c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 5646c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 565260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _remote_process_alive(self): 566260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Tests whether the remote devserver process is running.""" 567260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if not self._devserver_pid: 568260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return False 569260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold remote_cmd = 'test -e /proc/%s' % self._devserver_pid 570260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold result = self._devserver_ssh.run(remote_cmd, ignore_status=True) 571260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return result.exit_status == 0 5726c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 5736c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 5746c55bdb98e967675456a71a0971b81058536cac8Chris Sosa def get_netloc(self): 5756c55bdb98e967675456a71a0971b81058536cac8Chris Sosa """Returns the netloc (host:port) of the devserver.""" 576260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if not (self._devserver_pid and self._devserver_port): 5770338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold raise error.TestError('No running omaha/devserver') 5786c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 579260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return '%s:%s' % (self._omaha_host, self._devserver_port) 5800ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 5816c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 5822f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa def get_update_url(self): 5832f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Returns the update_url you can use to update via this server.""" 5842f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa return urlparse.urlunsplit(('http', self.get_netloc(), '/update', 5852f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa '', '')) 5862f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 5872f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 588260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _get_devserver_file_content(self, filename): 589260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Returns the content of a file on the devserver.""" 590260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return self._devserver_ssh.run_output('cat %s' % filename) 591260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 592260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 593260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _get_devserver_log(self): 594260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Obtain the devserver output.""" 595260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return self._get_devserver_file_content(self._devserver_logfile) 596260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 597260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 598238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo def _get_devserver_stdout(self): 599238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo """Obtain the devserver output in stdout and stderr.""" 600238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo return self._get_devserver_file_content(self._devserver_stdoutfile) 601238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo 602238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo 603260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _dump_devserver_log(self, logging_level=logging.ERROR): 6043563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa """Dump the devserver log to the autotest log. 60519426059c61c1b318b5d4bd04d70dacb63ec827dChris Sosa 60619426059c61c1b318b5d4bd04d70dacb63ec827dChris Sosa @param logging_level: logging level (from logging) to log the output. 60719426059c61c1b318b5d4bd04d70dacb63ec827dChris Sosa """ 608238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo logging.log(logging_level, "devserver stdout and stderr:\n" + 6093c18e75cd74416aae9d8e0fbe2719a0b36ace70fAlex Deymo self._get_devserver_stdout()) 610238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo logging.log(logging_level, "devserver logfile:\n" + 611238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo self._get_devserver_log()) 6120ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6130ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6140ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @staticmethod 6150ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def _split_url(url): 6162f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Splits a URL into the URL base and path.""" 6170ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold split_url = urlparse.urlsplit(url) 6180ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold url_base = urlparse.urlunsplit( 6192f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa (split_url.scheme, split_url.netloc, '', '', '')) 6202f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa url_path = split_url.path 6212f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa return url_base, url_path.lstrip('/') 6220ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 624260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def stop_devserver(self): 625260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Kill remote process and wait for it to die, dump its output.""" 6266c55bdb98e967675456a71a0971b81058536cac8Chris Sosa if not self._devserver_pid: 627ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa logging.error('No running omaha/devserver.') 628ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa return 6296c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 6300338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Killing omaha/devserver') 631260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._kill_remote_process() 63219426059c61c1b318b5d4bd04d70dacb63ec827dChris Sosa logging.debug('Final devserver log before killing') 633260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._dump_devserver_log(logging.DEBUG) 6343563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._cleanup_devserver_files() 6350ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6360ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6370ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass autoupdate_EndToEndTest(test.test): 6380ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Complete update test between two Chrome OS releases. 6390ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6400ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold Performs an end-to-end test of updating a ChromeOS device from one version 6410ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold to another. This script requires a running (possibly remote) servod 6420ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold instance connected to an actual servo board, which controls the DUT. It 6430ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold also assumes that a corresponding target (update) image was staged for 644ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa download on a central staging devserver. 6450ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6460ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold The test performs the following steps: 6470ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6480ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 0. Stages the source image and target update payload on the central 6490ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold Lorry/devserver. 6500ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1. Spawns a private Omaha/devserver instance, configured to return the 6510ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold target (update) image URL in response for an update check. 6520ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2. Connects to servod. 6530ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold a. Resets the DUT to a known initial state. 6540ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold b. Installs a source image on the DUT via recovery. 6550ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3. Reboots the DUT with the new image. 6560ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 4. Triggers an update check at the DUT. 6570ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 5. Watches as the DUT obtains an update and applies it. 6580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6. Repeats 3-5, ensuring that the next update check shows the new image 6590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold version. 6600ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 661ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa Some notes on naming: 662ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa devserver: Refers to a machine running the Chrome OS Update Devserver. 663ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver: An autotest wrapper to interact with a devserver. 664ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa Can be used to stage artifacts to a devserver. While 665ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa this can also be used to update a machine, we do not 666ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa use it for that purpose in this test as we manage 667ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa updates with out own devserver instances (see below). 668ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa omaha_devserver: This test's wrapper of a devserver running for the 669ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa purposes of emulating omaha. This test controls the 670ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa lifetime of this devserver instance and is separate 671ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa from the autotest lab's devserver's instances which are 672ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa only used for staging and hosting artifacts (because they 673ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa scale). These are run on the same machines as the actual 674ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest devservers which are used for staging but on 675ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa different ports. 676ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa *staged_url's: In this case staged refers to the fact that these items 677ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa are available to be downloaded statically from these urls 678ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa e.g. 'localhost:8080/static/my_file.gz'. These are usually 679ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa given after staging an artifact using a autotest_devserver 680ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa though they can be re-created given enough assumptions. 681ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa *update_url's: Urls refering to the update RPC on a given omaha devserver. 682ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa Since we always use an instantiated omaha devserver to run 683ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa updates, these will always reference an existing instance 684ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa of an omaha devserver that we just created for the purposes 685ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa of updating. 686ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa devserver_hostname: At the start of each test, we choose a devserver 687ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa machine in the lab for the test. We use the devserver 688ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa instance there (access by autotest_devserver) to stage 689ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa artifacts. However, we also use the same host to start 690ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa omaha devserver instances for updating machines with 691ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa (that reference the staged paylaods on the autotest 692ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa devserver instance). This hostname refers to that 693ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa machine we are using (since it's always the same for 694ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa both staging/omaha'ing). 695ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 6960ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 6970ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold version = 1 6980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6990ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # Timeout periods, given in seconds. 700f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa _WAIT_AFTER_SHUTDOWN_SECONDS = 10 701f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa _WAIT_AFTER_UPDATE_SECONDS = 20 702f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa _WAIT_FOR_USB_INSTALL_SECONDS = 4 * 60 703f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa _WAIT_FOR_MP_RECOVERY_SECONDS = 8 * 60 7040ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold _WAIT_FOR_INITIAL_UPDATE_CHECK_SECONDS = 12 * 60 7054f4426a2184828ad195fbb0b66b34f809a619236Chris Sosa # TODO(sosa): Investigate why this needs to be so long (this used to be 7064f4426a2184828ad195fbb0b66b34f809a619236Chris Sosa # 120 and regressed). 7074f4426a2184828ad195fbb0b66b34f809a619236Chris Sosa _WAIT_FOR_DOWNLOAD_STARTED_SECONDS = 4 * 60 7086c55bdb98e967675456a71a0971b81058536cac8Chris Sosa _WAIT_FOR_DOWNLOAD_COMPLETED_SECONDS = 10 * 60 709f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa _WAIT_FOR_UPDATE_COMPLETED_SECONDS = 4 * 60 7100ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold _WAIT_FOR_UPDATE_CHECK_AFTER_REBOOT_SECONDS = 15 * 60 71103901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold _DEVSERVER_HOSTLOG_REQUEST_TIMEOUT_SECONDS = 30 7120ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 71315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold _STATEFUL_UPDATE_FILENAME = 'stateful.tgz' 714c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen _LOGINABLE_MINIMUM_RELEASE = 5110 71515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 7162f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # Named tuple containing urls for staged urls needed for test. 7172f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # source_url: url to find the update payload for the source image. 7182f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # source_stateful_url: url to find the stateful payload for the source 7192f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # image. 7202f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # target_url: url to find the update payload for the target image. 7212f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # target_stateful_url: url to find the stateful payload for the target 7222f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # image. 7232f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa _STAGED_URLS = collections.namedtuple( 7242f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 'StagedUrls', 7252f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa ['source_url', 'source_stateful_url', 'target_url', 7262f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 'target_stateful_url']) 7272f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 7280ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 729f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa def _servo_dut_power_up(self): 7300ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Powers up the DUT, optionally simulating a Ctrl-D key press.""" 731f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._host.servo.power_short_press() 732f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._dev_mode: 733f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._host.servo.pass_devmode() 7340ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7350ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 736f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa def _servo_dut_reboot(self, disconnect_usbkey=False): 7370ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Reboots a DUT. 7380ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 739e7bd9369b76e2bbdc230c3c1aeb9afc6e6ec60baVadim Bendebury @param disconnect_usbkey: detach USB flash device from the DUT before 740e7bd9369b76e2bbdc230c3c1aeb9afc6e6ec60baVadim Bendebury powering it back up; this is useful when (for example) a USB 741e7bd9369b76e2bbdc230c3c1aeb9afc6e6ec60baVadim Bendebury booted device need not see the attached USB key after the 742e7bd9369b76e2bbdc230c3c1aeb9afc6e6ec60baVadim Bendebury reboot. 7430ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7440ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @raise error.TestFail if DUT fails to reboot. 7450ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7460ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 7470338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Rebooting dut') 748f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._host.servo.power_long_press() 7490ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold _wait(self._WAIT_AFTER_SHUTDOWN_SECONDS, 'after shutdown') 750e7bd9369b76e2bbdc230c3c1aeb9afc6e6ec60baVadim Bendebury if disconnect_usbkey: 751f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._host.servo.switch_usbkey('host') 752f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 753f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._servo_dut_power_up() 754f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_test_image: 755f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if not self._host.wait_up(timeout=self._host.BOOT_TIMEOUT): 7560ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold raise error.TestFail( 7570338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'DUT %s failed to boot after %d secs' % 758f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa (self._host.ip, self._host.BOOT_TIMEOUT)) 7590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold else: 760cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold # TODO(garnold) chromium-os:33766: implement waiting for MP-signed 761cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold # images; ideas include waiting for a ping reply, or using a GPIO 762cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold # signal. 763cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold pass 7640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7650ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 766ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def _install_mp_image(self, staged_image_url): 7670ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Installs an MP-signed recovery image on a DUT. 7680ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 769ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param staged_image_url: URL of the image on a Lorry/devserver 7700ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 7710ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # Flash DUT with source image version, using recovery. 7720338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Installing source mp-signed image via recovery: %s', 773ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa staged_image_url) 774f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._host.servo.install_recovery_image( 775ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa staged_image_url, 7760ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold wait_timeout=self._WAIT_FOR_MP_RECOVERY_SECONDS) 7770ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7780ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # Reboot the DUT after installation. 779f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._servo_dut_reboot(disconnect_usbkey=True) 7800ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7810ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 782ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def _install_test_image_with_servo(self, staged_image_url): 7830ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Installs a test image on a DUT, booted via recovery. 7840ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 785ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param staged_image_url: URL of the image on the devserver 7860ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param is_dev_nmode: whether or not the DUT is in dev mode 7870ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7880ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @raise error.TestFail if DUT cannot boot the test image from USB; 7890ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold AutotestHostRunError if failed to run the install command on the 7900ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold DUT. 7910ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7920ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 7930338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Installing source test image via recovery: %s', 794ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa staged_image_url) 795ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._host.servo.install_recovery_image(staged_image_url) 7960338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Waiting for image to boot') 797f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if not self._host.wait_up(timeout=self._host.USB_BOOT_TIMEOUT): 798cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold raise error.TestFail( 799cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 'DUT %s boot from usb timed out after %d secs' % 800cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold (self._host, self._host.USB_BOOT_TIMEOUT)) 8010338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Installing new image onto ssd') 8020ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold try: 803f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa cmd_result = self._host.run( 8040ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'chromeos-install --yes', 8050ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold timeout=self._WAIT_FOR_USB_INSTALL_SECONDS, 8060ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold stdout_tee=None, stderr_tee=None) 807f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa except error.AutotestHostRunError: 8080ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # Dump stdout (with stderr) to the error log. 8090338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.error('Command failed, stderr:\n' + cmd_result.stderr) 8100ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold raise 8110ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8120ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # Reboot the DUT after installation. 813f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._servo_dut_reboot(disconnect_usbkey=True) 8140ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8150ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8162f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa def _trigger_test_update(self, omaha_devserver): 8170ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Trigger an update check on a test image. 8180ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8192f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param omaha_devserver: Instance of OmahaDevserver that will serve the 8202f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa update. 8210ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @raise RootFSUpdateError if anything went wrong. 8220ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 8242f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa updater = autoupdater.ChromiumOSUpdater( 8252f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa omaha_devserver.get_update_url(), host=self._host) 8260ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold updater.trigger_update() 8270ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8280ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 829f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa def _get_rootdev(self): 83009706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold """Returns the partition device containing the rootfs on a host. 83109706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 83209706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold @return The rootfs partition device (string). 83309706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 83409706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold @raise AutotestHostRunError if command failed to run on host. 83509706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 83609706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold """ 83766d74078caa789f80d4a43c82b61d6016a0cf430Chris Sosa return self._host.run('rootdev -s').stdout.strip() 83809706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 83909706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 840ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def _stage_image(self, autotest_devserver, image_uri): 841ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Stage a Chrome OS image onto a staging devserver. 8420ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 843ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param autotest_devserver: instance of client.common_lib.dev_server to 844ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa use to stage the image. 845ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa @param image_uri: The uri of the image. 846ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @return URL of the staged image on the staging devserver. 8470ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8480ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @raise error.TestError if there's a problem with staging. 8490ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8500ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 851f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_test_image: 8520ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # For this call, we just need the URL path up to the image.zip file 8530ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # (exclusive). 8540ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold image_uri_path = urlparse.urlsplit(image_uri).path.partition( 8550ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'image.zip')[0].strip('/') 8560ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold try: 857ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver.stage_artifacts(image_uri_path, 858ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa ['test_image']) 859ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa return autotest_devserver.get_test_image_url(image_uri_path) 8600ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold except dev_server.DevServerException, e: 8610ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold raise error.TestError( 8620338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'Failed to stage source test image: %s' % e) 8630ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold else: 8640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # TODO(garnold) chromium-os:33766: implement staging of MP-signed 8650ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # images. 8662f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa raise NotImplementedError() 8670ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8680ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 869cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @staticmethod 870cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold def _stage_payload(autotest_devserver, devserver_label, filename, 87172f48be6c3f7e30edc6ff9a785f9c4cb53521af4Don Garrett archive_url=None): 8722f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Stage the given payload onto the devserver. 8730ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8742f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa Works for either a stateful or full/delta test payload. Expects the 8752f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa gs_path or a combo of devserver_label + filename. 8760ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 877ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param autotest_devserver: instance of client.common_lib.dev_server to 878ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa use to reach the devserver instance for this 879ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa build. 8802f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param devserver_label: The build name e.g. x86-mario-release/<version>. 8812f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa If set, assumes default gs archive bucket and 8822f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa requires filename to be specified. 8832f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param filename: In conjunction with devserver_label, if just specifying 8842f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa the devserver label name, this is which file are you 8852f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa downloading. 88615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @param archive_url: An optional GS archive location, if not using the 88715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold devserver's default. 888ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa 8890ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return URL of the staged payload on the server. 8900ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8910ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @raise error.TestError if there's a problem with staging. 8920ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8930ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 8942f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa try: 895ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver.stage_artifacts( 89672f48be6c3f7e30edc6ff9a785f9c4cb53521af4Don Garrett image=devserver_label, files=[filename], 89772f48be6c3f7e30edc6ff9a785f9c4cb53521af4Don Garrett archive_url=archive_url) 898ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa return autotest_devserver.get_staged_file_url(filename, 899ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa devserver_label) 9002f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa except dev_server.DevServerException, e: 9010338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold raise error.TestError('Failed to stage payload: %s' % e) 9020ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 9030ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 90472f48be6c3f7e30edc6ff9a785f9c4cb53521af4Don Garrett def _stage_payload_by_uri(self, autotest_devserver, payload_uri): 90515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """Stage a payload based on its GS URI. 90615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 90715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold This infers the build's label, filename and GS archive from the 90815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold provided GS URI. 90915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 91015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @param autotest_devserver: instance of client.common_lib.dev_server to 91115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold use to reach the devserver instance for this 91215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold build. 91315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @param payload_uri: The full GS URI of the payload. 91415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 91515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @return URL of the staged payload on the server. 91615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 91715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @raise error.TestError if there's a problem with staging. 91815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 91915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """ 92015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold archive_url, _, filename = payload_uri.rpartition('/') 92115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold devserver_label = urlparse.urlsplit(archive_url).path.strip('/') 92215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold return self._stage_payload(autotest_devserver, devserver_label, 92372f48be6c3f7e30edc6ff9a785f9c4cb53521af4Don Garrett filename, archive_url=archive_url) 92415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 92515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 926cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @staticmethod 927cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold def _payload_to_update_url(payload_url): 9282f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Given a update or stateful payload url, returns the update url.""" 9297231260da421abdf5ceceff6ab60155936dca21fChris Sosa # We want to transform it to the correct omaha url which is 9307231260da421abdf5ceceff6ab60155936dca21fChris Sosa # <hostname>/update/...LABEL. 9312f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa base_url = payload_url.rpartition('/')[0] 9322f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa return base_url.replace('/static/', '/update/') 9332f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 9342f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 93515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold def _get_stateful_uri(self, build_uri): 93615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """Returns a complete GS URI of a stateful update given a build path.""" 93715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold return '/'.join([build_uri.rstrip('/'), self._STATEFUL_UPDATE_FILENAME]) 93815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 93915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 94015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold def _payload_to_stateful_uri(self, payload_uri): 94115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """Given a payload GS URI, returns the corresponding stateful URI.""" 94215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold build_uri = payload_uri.rpartition('/')[0] 94315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold return self._get_stateful_uri(build_uri) 9442f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 9452f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 9462f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa def update_via_test_payloads(self, omaha_host, payload_url, stateful_url, 9472f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa clobber): 948cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Given the following update and stateful urls, update the DUT. 949cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 950cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold Only updates the rootfs/stateful if the respective url is provided. 951cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 952cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param omaha_host: If updating rootfs, redirect updates through this 953cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold host. Should be None iff payload_url is None. 954cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param payload_url: If set, the specified url to find the update 955cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold payload. 956cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param stateful_url: If set, the specified url to find the stateful 957cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold payload. 958cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param clobber: If True, do a clean install of stateful. 959cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """ 960cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold def perform_update(url, is_stateful): 961cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Perform a rootfs/stateful update using given URL. 962cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 963cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param url: URL to update from. 964cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param is_stateful: Whether this is a stateful or rootfs update. 965cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """ 966cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if url: 967cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold updater = autoupdater.ChromiumOSUpdater(url, host=self._host) 968cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if is_stateful: 969cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold updater.update_stateful(clobber=clobber) 970cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold else: 971cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold updater.update_rootfs() 972cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 973cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold # We create a OmahaDevserver to redirect blah.bin to update/. This 974cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold # allows us to use any payload filename to serve an update. 975cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold temp_devserver = None 976cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold try: 977cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if payload_url: 978cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold temp_devserver = OmahaDevserver( 979260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold omaha_host, self._devserver_dir, payload_url) 980cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold temp_devserver.start_devserver() 981cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold payload_url = temp_devserver.get_update_url() 982cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 983cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold stateful_url = self._payload_to_update_url(stateful_url) 984cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 985cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold perform_update(payload_url, False) 986cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold perform_update(stateful_url, True) 987cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold finally: 988cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if temp_devserver: 989260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold temp_devserver.stop_devserver() 9902f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 9912f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 992ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def install_source_version(self, devserver_hostname, image_url, 993ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa stateful_url): 9942f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Prepare the specified host with the image given by the urls. 9952f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 996ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param devserver_hostname: If updating rootfs, redirect updates 997ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa through this host. Should be None iff 998ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa image_url is None. 9992f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param image_url: If set, the specified url to find the source image 10002f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa or full payload for the source image. 10012f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param stateful_url: If set, the specified url to find the stateful 10022f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa payload. 10032f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """ 1004f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_servo: 1005f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # Install source image (test vs MP). 1006f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_test_image: 1007f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._install_test_image_with_servo(image_url) 1008f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa else: 1009f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._install_mp_image(image_url) 1010f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1011f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa else: 101245f02ae47134953169805d281992c9edf0019250Chris Sosa try: 10132f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # Reboot to get us into a clean state. 10142f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa self._host.reboot() 10152f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # Since we are installing the source image of the test, clobber 10162f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # stateful. 1017ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self.update_via_test_payloads(devserver_hostname, image_url, 10182f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa stateful_url, clobber=True) 10192f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa self._host.reboot() 102045f02ae47134953169805d281992c9edf0019250Chris Sosa except error.AutoservRunError: 102145f02ae47134953169805d281992c9edf0019250Chris Sosa logging.fatal('Error re-imaging the machine with the source ' 102245f02ae47134953169805d281992c9edf0019250Chris Sosa 'image %s', image_url) 10238577f8fb064fc8392bdc399fdd7465307d6da03bAlex Miller raise error.TestError('Could not update to pre-conditions of ' 10248577f8fb064fc8392bdc399fdd7465307d6da03bAlex Miller 'the test: we failed to start the ' 10258577f8fb064fc8392bdc399fdd7465307d6da03bAlex Miller 'private devserver, connect to the host ' 10268577f8fb064fc8392bdc399fdd7465307d6da03bAlex Miller 'and/or make it reboot.') 1027f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1028f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1029ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def stage_artifacts_onto_devserver(self, autotest_devserver, test_conf): 10302f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Stages artifacts that will be used by the test onto the devserver. 10312f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 1032ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param autotest_devserver: instance of client.common_lib.dev_server to 1033ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa use to reach the devserver instance for this 1034ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa build. 10352f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param test_conf: a dictionary containing test configuration values 10362f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 10372f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @return a _STAGED_URLS tuple containing the staged urls. 1038f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa """ 10390338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Staging images onto autotest devserver (%s)', 1040ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver.url()) 1041f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 104215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_source_url = None 104315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_source_stateful_url = None 1044fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold source_image_uri = test_conf['source_image_uri'] 1045fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold if source_image_uri: 1046fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold if self._use_servo: 1047fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold staged_source_url = self._stage_image( 1048fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold autotest_devserver, source_image_uri) 1049fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold # Test image already contains a stateful update, leave 1050fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold # staged_source_stateful_url untouhced. 10512f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa else: 1052fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold staged_source_url = self._stage_payload_by_uri( 1053fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold autotest_devserver, source_image_uri) 1054fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold 1055fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold # In order to properly install the source image using a full 1056fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold # payload we'll also need the stateful update that comes with it. 1057fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold # In general, tests may have their source artifacts in a different 1058fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold # location than their payloads. This is determined by whether or 1059fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold # not the source_archive_uri attribute is set; if it isn't set, 1060fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold # then we derive it from the dirname of the source payload. 1061fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold source_archive_uri = test_conf.get('source_archive_uri') 1062fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold if source_archive_uri: 1063fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold source_stateful_uri = self._get_stateful_uri(source_archive_uri) 1064fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold else: 1065fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold source_stateful_uri = self._payload_to_stateful_uri( 1066fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold source_image_uri) 1067fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold 1068fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold staged_source_stateful_url = self._stage_payload_by_uri( 1069fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold autotest_devserver, source_stateful_uri) 107015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 1071fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold # Log source image URLs. 1072fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold logging.info('Source %s from %s staged at %s', 1073fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold 'image' if self._use_servo else 'full payload', 1074fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold source_image_uri, staged_source_url) 1075fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold if staged_source_stateful_url: 1076fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold logging.info('Source stateful update from %s staged at %s', 1077fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold source_stateful_uri, staged_source_stateful_url) 107815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 107915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_payload_uri = test_conf['target_payload_uri'] 108015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_url = self._stage_payload_by_uri( 108115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold autotest_devserver, target_payload_uri) 108215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri = None 108315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_archive_uri = test_conf.get('target_archive_uri') 108415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold if not target_archive_uri and self._job_repo_url: 10852f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa _, devserver_label = tools.get_devserver_build_from_package_url( 10862f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa self._job_repo_url) 108715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_stateful_url = self._stage_payload( 108815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold autotest_devserver, devserver_label, 108915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold self._STATEFUL_UPDATE_FILENAME) 10902f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa else: 109115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold if target_archive_uri: 109215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri = self._get_stateful_uri(target_archive_uri) 109315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold else: 109415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri = self._payload_to_stateful_uri( 109515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_payload_uri) 1096f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 109715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_stateful_url = self._stage_payload_by_uri( 109815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold autotest_devserver, target_stateful_uri) 10992f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 1100fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold # Log target payload URLs. 110115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold logging.info('%s test payload from %s staged at %s', 110215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold test_conf['update_type'], target_payload_uri, 110315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_url) 11040338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Target stateful update from %s staged at %s', 110515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri or 'standard location', 110615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_stateful_url) 110715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 110815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold return self._STAGED_URLS(staged_source_url, staged_source_stateful_url, 110915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_url, staged_target_stateful_url) 1110f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1111f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1112f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa def initialize(self): 1113f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa """Sets up variables that will be used by test.""" 1114f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._host = None 1115f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._use_servo = False 1116f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._dev_mode = False 1117f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._omaha_devserver = None 1118f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1119f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._use_test_image = True 11202f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa self._job_repo_url = None 1121f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._devserver_dir = global_config.global_config.get_config_value( 1122f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 'CROS', 'devserver_dir', default=None) 1123f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._devserver_dir is None: 1124f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa raise error.TestError( 11250338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'Path to devserver source tree not provided; please define ' 1126f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 'devserver_dir under [CROS] in your shadow_config.ini') 1127f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1128f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1129f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa def cleanup(self): 1130f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa """Kill the omaha devserver if it's still around.""" 1131f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._omaha_devserver: 1132260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._omaha_devserver.stop_devserver() 1133f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1134f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._omaha_devserver = None 1135f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1136f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 113745f02ae47134953169805d281992c9edf0019250Chris Sosa def _verify_preconditions(self): 1138f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa """Validate input args make sense.""" 1139f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_servo and not self._host.servo: 1140f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa raise error.AutotestError('Servo use specified but no servo ' 1141f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 'attached to host object.') 1142f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1143f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if not self._use_test_image and not self._use_servo: 11440338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold raise error.TestError('Cannot install mp image without servo.') 1145f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1146f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1147c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen def _run_login_test(self, release_string): 1148c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen """Runs login_LoginSuccess test if it is supported by the release.""" 1149c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # Only do login tests with recent builds, since they depend on 1150c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # some binary compatibility with the build itself. 1151c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # '5116.0.0' -> ('5116', '0', '0') -> 5116 1152c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen if int(release_string.split('.')[0]) > self._LOGINABLE_MINIMUM_RELEASE: 1153c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # Login, to prove we can before/after the update. 1154c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen logging.info('Attempting to login (release %s).', release_string) 1155c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1156c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen client_at = autotest.Autotest(self._host) 1157c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen client_at.run_test('login_LoginSuccess') 1158c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen else: 1159c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen logging.info('Not attempting login test because %s is older than ' 1160c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen '%d.', release_string, self._LOGINABLE_MINIMUM_RELEASE) 1161c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1162c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1163ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def _dump_update_engine_log(self): 1164ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Dumps relevant AU error log.""" 116545f02ae47134953169805d281992c9edf0019250Chris Sosa if not self._use_servo: 116645f02ae47134953169805d281992c9edf0019250Chris Sosa logging.error('Test failed -- dumping snippet of update_engine log') 1167ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa try: 1168ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa error_log = self._host.run_output( 1169ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 'tail -n 40 /var/log/update_engine.log') 1170ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa logging.error(error_log) 1171ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa except Exception: 1172ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # Mute any exceptions we get printing debug logs. 1173ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa pass 117445f02ae47134953169805d281992c9edf0019250Chris Sosa 11750ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 117631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen def _start_perf_mon(self): 117731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """Starts monitoring performance and resource usage on a DUT. 117831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 117931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen Call _stop_perf_mon() with the returned PID to stop monitoring 118031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen and collect the results. 118131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 118231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen @return the PID of the newly created DUT monitoring process. 118331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """ 118431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # We can't assume much about the source image so we copy the 118531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # performance monitoring script to the DUT directly. 118631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen path = os.path.join(self.bindir, 'update_engine_performance_monitor.py') 118731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen self._host.send_file(path, '/tmp') 118831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen cmd = 'python /tmp/update_engine_performance_monitor.py --start-bg' 118931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen return int(self._host.run(cmd).stdout) 119031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 119131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 119231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen def _stop_perf_mon(self, perf_mon_pid): 119331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """Stops monitoring performance and resource usage on a DUT. 119431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 119531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen The PID returned from _start_perf_mon() should be passed 119631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen in. See update_engine_performance_monitor.py for known 119731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen attributes (e.g. |rss_peak|). 119831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 119931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen @param perf_mon_pid: the PID returned from _start_perf_mon(). 120031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 120131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen @return a Python object created by deserializing JSON or None 120231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen if an error occured. 120331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """ 120431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Gracefully handle problems with performance monitoring by 120531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # just returning None. 120631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen try: 120731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen cmd = ('python /tmp/update_engine_performance_monitor.py ' 120831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen '--stop-bg=%d') % perf_mon_pid 120931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen perf_json_txt = self._host.run(cmd).stdout 121031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen return json.loads(perf_json_txt) 121131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen except Exception as e: 121231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen logging.warning('Failed to parse output from ' 121331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'update_engine_performance_monitor.py: %s', e) 121431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen return None 121531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 121631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 121731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen def _report_perf_data(self, perf_data): 121831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """Reports performance and resource data. 121931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 122031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen @param perf_data: the value obtained from _stop_perf_mon(). 122131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """ 122231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen rss_peak = perf_data.get('rss_peak') 122331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen if rss_peak: 122431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen rss_peak_kib = rss_peak / 1024 122531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen logging.info('Peak memory (RSS) usage on DUT: %d KiB', rss_peak_kib) 122631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen self.output_perf_value(description='mem_usage_peak', 122731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen value=int(rss_peak_kib), 122831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen units='KiB', 122931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen higher_is_better=False) 123031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen else: 123131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen logging.warning('No rss_peak key in JSON returned by ' 123231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'update_engine_performance_monitor.py') 123331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 123431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1235ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def run_update_test(self, staged_urls, test_conf): 1236ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Runs the actual update test once preconditions are met. 12370ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1238ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param staged_urls: A _STAGED_URLS tuple containing the staged urls. 1239ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param test_conf: A dictionary containing test configuration values 12400ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1241ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify an update 1242ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa event. 12430ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 1244c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1245f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # On test images, record the active root partition. 1246f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa source_rootfs_partition = None 1247f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_test_image: 1248f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa source_rootfs_partition = self._get_rootdev() 12490338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Source image rootfs partition: %s', 1250f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa source_rootfs_partition) 12510ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 125231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Start the performance monitoring process on the DUT. 125331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen perf_mon_pid = self._start_perf_mon() 125431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen try: 125531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Trigger an update. 125631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen if self._use_test_image: 125731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen self._trigger_test_update(self._omaha_devserver) 125831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen else: 125931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # TODO(garnold) chromium-os:33766: use GPIOs to trigger an 126031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # update. 126131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen pass 12620ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 126331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Track update progress. 126431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen omaha_netloc = self._omaha_devserver.get_netloc() 126531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen omaha_hostlog_url = urlparse.urlunsplit( 126631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen ['http', omaha_netloc, '/api/hostlog', 126731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'ip=' + self._host.ip, '']) 126831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen logging.info('Polling update progress from omaha/devserver: %s', 126931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen omaha_hostlog_url) 127031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen log_verifier = UpdateEventLogVerifier( 127131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen omaha_hostlog_url, 127231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen self._DEVSERVER_HOSTLOG_REQUEST_TIMEOUT_SECONDS) 127331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 127431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Verify chain of events in a successful update process. 127531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen chain = ExpectedUpdateEventChain( 127631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen (self._WAIT_FOR_INITIAL_UPDATE_CHECK_SECONDS, 127731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen ExpectedUpdateEvent( 127831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen version=test_conf['source_release'], 127931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen error_message=('Failed to receive initial update ' 128031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'check. Check Omaha devserver log in ' 128131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'this output.'))), 128231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen (self._WAIT_FOR_DOWNLOAD_STARTED_SECONDS, 128331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen ExpectedUpdateEvent( 128431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen event_type=EVENT_TYPE_DOWNLOAD_STARTED, 128531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen event_result=EVENT_RESULT_SUCCESS, 128631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen version=test_conf['source_release'], 128731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen error_message=( 128831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'Failed to start the download of the update ' 128931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'payload from the staging server. Check both ' 129031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'the omaha log and update_engine.log in ' 129131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'sysinfo (or on the DUT).'))), 129231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen (self._WAIT_FOR_DOWNLOAD_COMPLETED_SECONDS, 129331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen ExpectedUpdateEvent( 129431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen event_type=EVENT_TYPE_DOWNLOAD_FINISHED, 129531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen event_result=EVENT_RESULT_SUCCESS, 129631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen version=test_conf['source_release'], 129731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen error_message=( 129831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'Failed to finish download from devserver. ' 129931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'Check the update_engine.log in sysinfo (or ' 130031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'on the DUT).'))), 130131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen (self._WAIT_FOR_UPDATE_COMPLETED_SECONDS, 130231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen ExpectedUpdateEvent( 130331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen event_type=EVENT_TYPE_UPDATE_COMPLETE, 130431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen event_result=EVENT_RESULT_SUCCESS, 130531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen version=test_conf['source_release'], 130631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen error_message=( 130731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'Failed to complete update before reboot. ' 130831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'Check the update_engine.log in sysinfo (or ' 130931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'on the DUT).')))) 131031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 131131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen log_verifier.verify_expected_event_chain(chain) 131231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 131331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Wait after an update completion (safety margin). 131431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen _wait(self._WAIT_AFTER_UPDATE_SECONDS, 'after update completion') 131531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen finally: 131631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Terminate perf monitoring process and collect its output. 131731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen perf_data = self._stop_perf_mon(perf_mon_pid) 131831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen if perf_data: 131931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen self._report_perf_data(perf_data) 1320f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1321f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # Reboot the DUT after the update. 1322ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa if self._use_servo: 1323f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._servo_dut_reboot() 1324f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa else: 13252f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # Only update the stateful partition since the test has updated the 13262f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # rootfs. 13272f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa self.update_via_test_payloads( 13282f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa None, None, staged_urls.target_stateful_url, clobber=False) 1329f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._host.reboot() 13300ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1331f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # Trigger a second update check (again, test vs MP). 1332f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_test_image: 13332f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa self._trigger_test_update(self._omaha_devserver) 1334f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa else: 1335f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # TODO(garnold) chromium-os:33766: use GPIOs to trigger an 1336f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # update. 1337f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa pass 13380ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1339f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # Observe post-reboot update check, which should indicate that the 1340f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # image version has been updated. 1341f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa chain = ExpectedUpdateEventChain( 1342f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa (self._WAIT_FOR_UPDATE_CHECK_AFTER_REBOOT_SECONDS, 1343f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa ExpectedUpdateEvent( 13440338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold event_type=EVENT_TYPE_UPDATE_COMPLETE, 13450338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold event_result=EVENT_RESULT_SUCCESS_REBOOT, 1346f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa version=test_conf['target_release'], 1347ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa previous_version=test_conf['source_release'], 13480338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold error_message=( 13490338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'Failed to reboot into the target version after ' 13500338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'an update. Check the sysinfo logs. This probably ' 13510338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'means that the updated image failed to verify ' 13520338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'after reboot and might mean that the update ' 13530338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'payload is bad')))) 1354ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1355ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa log_verifier.verify_expected_event_chain(chain) 1356f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1357f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # On test images, make sure we're using a different partition after 1358f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # the update. 1359f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_test_image: 1360f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa target_rootfs_partition = self._get_rootdev() 1361f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if target_rootfs_partition == source_rootfs_partition: 1362f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa raise error.TestFail( 13630338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'Rootfs partition did not change (%s)' % 1364f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa target_rootfs_partition) 13650ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 13660338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info( 13670338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'Target image rootfs partition changed as expected: %s', 13680338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold target_rootfs_partition) 13690338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 13700338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Update successful, test completed') 13710ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1372ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1373ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def run_once(self, host, test_conf, use_servo): 1374ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Performs a complete auto update test. 1375ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1376ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param host: a host object representing the DUT 1377ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param test_conf: a dictionary containing test configuration values 1378ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param use_servo: True whether we should use servo. 1379ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1380ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raise error.TestError if anything went wrong with setting up the test; 1381ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa error.TestFail if any part of the test has failed. 1382ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1383ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """ 1384f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 1385f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett if not test_conf['target_release']: 1386f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett raise RequiredArgumentMissing( 1387f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 'target_release is a required argument.') 1388f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 1389ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # Attempt to get the job_repo_url to find the stateful payload for the 1390ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # target image. 1391ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa try: 1392ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._job_repo_url = host.lookup_job_repo_url() 1393ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa except KeyError: 1394ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa logging.warning('Job Repo URL not found. Assuming stateful ' 1395ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 'payload can be found along with the target update') 1396ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1397ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._host = host 1398ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._use_test_image = test_conf.get('image_type') != 'mp' 1399ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._use_servo = use_servo 1400ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa if self._use_servo: 1401ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._dev_mode = self._host.servo.get('dev_mode') == 'on' 1402ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1403ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # Verify that our arguments are sane. 1404ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._verify_preconditions() 1405ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1406009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # Find a devserver to use. We first try to pick a devserver with the 1407009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # least load. In case all devservers' load are higher than threshold, 1408009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # fall back to the old behavior by picking a devserver based on the 1409009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # payload URI, with which ImageServer.resolve will return a random 1410009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # devserver based on the hash of the URI. 14114e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi least_loaded_devserver = dev_server.get_least_loaded_devserver() 14124e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi if least_loaded_devserver: 14134e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi logging.debug('Choose the least loaded devserver: %s', 14144e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi least_loaded_devserver) 14154e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi autotest_devserver = dev_server.ImageServer(least_loaded_devserver) 14164e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi else: 1417009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi logging.warning('No devserver meets the maximum load requirement. ' 1418009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi 'Pick a random devserver to use.') 1419009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi autotest_devserver = dev_server.ImageServer.resolve( 1420009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi test_conf['target_payload_uri']) 1421ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa devserver_hostname = urlparse.urlparse( 1422ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver.url()).hostname 1423d874a4d63dacfb6e8a74466eab5160e940aaa690Dan Shi counter_key = dev_server.ImageServer.create_stats_str( 1424d874a4d63dacfb6e8a74466eab5160e940aaa690Dan Shi 'paygen', devserver_hostname, artifacts=None) 1425d874a4d63dacfb6e8a74466eab5160e940aaa690Dan Shi metadata = {'devserver': devserver_hostname, 1426d874a4d63dacfb6e8a74466eab5160e940aaa690Dan Shi '_type': 'devserver_paygen'} 1427d874a4d63dacfb6e8a74466eab5160e940aaa690Dan Shi metadata.update(test_conf) 1428d874a4d63dacfb6e8a74466eab5160e940aaa690Dan Shi autotest_stats.Counter(counter_key, metadata=metadata).increment() 1429ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1430ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # Stage source images and update payloads onto a devserver. 1431ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa staged_urls = self.stage_artifacts_onto_devserver( 1432ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver, test_conf) 1433ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1434ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # Install the source version onto the DUT. 1435fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold if staged_urls.source_url: 1436fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold self.install_source_version(devserver_hostname, 1437fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold staged_urls.source_url, 1438fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold staged_urls.source_stateful_url) 1439ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1440ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._omaha_devserver = OmahaDevserver( 1441260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold devserver_hostname, self._devserver_dir, staged_urls.target_url) 1442ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._omaha_devserver.start_devserver() 1443c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1444c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # Make sure we can login before the update. 1445c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen self._run_login_test(test_conf['source_release']) 1446c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1447ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa try: 1448ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self.run_update_test(staged_urls, test_conf) 1449ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa except ExpectedUpdateEventChainFailed: 1450ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._dump_update_engine_log() 1451ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa raise 1452f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 1453c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # And make sure we can login after update. 1454c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen self._run_login_test(test_conf['target_release']) 1455