autoupdate_EndToEndTest.py revision 3563042207623fbb9db02018156e8b5fa0e4c2c3
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 178ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basifrom autotest_lib.server import autotest, hosts, test 182f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosafrom autotest_lib.server.cros.dynamic_suite import tools 190ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 200ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 210ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnolddef _wait(secs, desc=None): 220ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Emits a log message and sleeps for a given number of seconds.""" 230338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold msg = 'Waiting %s seconds' % secs 240ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if desc: 250ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold msg += ' (%s)' % desc 260ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold logging.info(msg) 270ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold time.sleep(secs) 280ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 290ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 30ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosaclass ExpectedUpdateEventChainFailed(error.TestFail): 31ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Raised if we fail to receive an expected event in a chain.""" 32ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 33f789cf3a52c720344062f0a6c782bb758f08b189Don Garrettclass RequiredArgumentMissing(error.TestFail): 34f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett """Raised if we fail to receive an expected event in a chain.""" 35f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 36ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 370338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold# Update event types. 380338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_DOWNLOAD_COMPLETE = '1' 390338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_INSTALL_COMPLETE = '2' 400338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_UPDATE_COMPLETE = '3' 410338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_DOWNLOAD_STARTED = '13' 420338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_DOWNLOAD_FINISHED = '14' 430338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 440338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold# Update event results. 450338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_ERROR = '0' 460338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_SUCCESS = '1' 470338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_SUCCESS_REBOOT = '2' 480338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_UPDATE_DEFERRED = '9' 490338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 500338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 510ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass ExpectedUpdateEvent(object): 52ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Defines an expected event in a host update process. 53ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 54ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa Attrs: 55ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa _expected_attrs: Dictionary of attributes that should match events 56ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa received. If attribute is not provided, assumes match. 57ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa error_message: What we should error out with if we fail to verify this 58ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa expected event. 59ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """ 6045f02ae47134953169805d281992c9edf0019250Chris Sosa 6145f02ae47134953169805d281992c9edf0019250Chris Sosa # Omaha event types/results, from update_engine/omaha_request_action.h 6245f02ae47134953169805d281992c9edf0019250Chris Sosa # These are stored in dict form in order to easily print out the keys. 630338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold _EVENT_TYPE_DICT = { 640338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_TYPE_DOWNLOAD_COMPLETE: 'download_complete', 650338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_TYPE_INSTALL_COMPLETE: 'install_complete', 660338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_TYPE_UPDATE_COMPLETE: 'update_complete', 670338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_TYPE_DOWNLOAD_STARTED: 'download_started', 680338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_TYPE_DOWNLOAD_FINISHED: 'download_finished' 690338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold } 700338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 710338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold _EVENT_RESULT_DICT = { 720338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_RESULT_ERROR: 'error', 730338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_RESULT_SUCCESS: 'success', 740338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_RESULT_SUCCESS_REBOOT: 'success_reboot', 750338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold EVENT_RESULT_UPDATE_DEFERRED: 'update_deferred' 760338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold } 770338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 780338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold _ATTR_NAME_DICT_MAP = { 790338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'event_type': _EVENT_TYPE_DICT, 800338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'event_result': _EVENT_RESULT_DICT, 810338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold } 820338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 830338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold _VALID_TYPES = set(_EVENT_TYPE_DICT.keys()) 840338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold _VALID_RESULTS = set(_EVENT_RESULT_DICT.keys()) 8545f02ae47134953169805d281992c9edf0019250Chris Sosa 860ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __init__(self, event_type=None, event_result=None, version=None, 87ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa previous_version=None, error_message=None): 880338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if event_type and event_type not in self._VALID_TYPES: 8945f02ae47134953169805d281992c9edf0019250Chris Sosa raise ValueError('event_type %s is not valid.' % event_type) 9045f02ae47134953169805d281992c9edf0019250Chris Sosa 910338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if event_result and event_result not in self._VALID_RESULTS: 9245f02ae47134953169805d281992c9edf0019250Chris Sosa raise ValueError('event_result %s is not valid.' % event_result) 9345f02ae47134953169805d281992c9edf0019250Chris Sosa 940ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._expected_attrs = { 950ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'event_type': event_type, 960ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'event_result': event_result, 970ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'version': version, 980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'previous_version': previous_version, 990ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold } 100ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self.error_message = error_message 1010ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1020ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1030338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold @staticmethod 1040338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold def _attr_val_str(attr_val, helper_dict, default=None): 1050338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """Returns an enriched attribute value string, or default.""" 1060338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if not attr_val: 1070338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return default 1080338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1090338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold s = str(attr_val) 1100338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if helper_dict: 1110338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold s += ':%s' % helper_dict.get(attr_val, 'unknown') 1120338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1130338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return s 1140338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1150338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1160338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold def _attr_name_and_values(self, attr_name, expected_attr_val, 1170338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual_attr_val=None): 1180338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """Returns an attribute name, expected and actual value strings. 1190338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1200338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold This will return (name, expected, actual); the returned value for 1210338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual will be None if its respective input is None/empty. 1220338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1230338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """ 1240338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold helper_dict = self._ATTR_NAME_DICT_MAP.get(attr_name) 1250338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold expected_attr_val_str = self._attr_val_str(expected_attr_val, 1260338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold helper_dict, 1270338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold default='any') 1280338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual_attr_val_str = self._attr_val_str(actual_attr_val, helper_dict) 1290338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1300338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return attr_name, expected_attr_val_str, actual_attr_val_str 1310338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1320338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1330ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __str__(self): 1340338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return ' '.join(['%s=%s' % 1350338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold self._attr_name_and_values(attr_name, attr_val)[0:2] 1360ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold for attr_name, attr_val 1370ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold in self._expected_attrs.iteritems()]) 1380ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1390ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1400ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def verify(self, actual_event): 1410ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verify the attributes of an actual event. 1420ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 143ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa @param actual_event: a dictionary containing event attributes 1440ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1450ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return True if all attributes as expected, False otherwise. 1460ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1470ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 1480ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return all([self._verify_attr(attr_name, expected_attr_val, 1490ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold actual_event.get(attr_name)) 1500ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold for attr_name, expected_attr_val 1510ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold in self._expected_attrs.iteritems() if expected_attr_val]) 1520ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1530ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1540ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def _verify_attr(self, attr_name, expected_attr_val, actual_attr_val): 1550ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies that an actual log event attributes matches expected on. 1560ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1570ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param attr_name: name of the attribute to verify 1580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param expected_attr_val: expected attribute value 1590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param actual_attr_val: actual attribute value 1600ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1610ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return True if actual value is present and matches, False otherwise. 1620ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1630ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 16445f02ae47134953169805d281992c9edf0019250Chris Sosa # None values are assumed to be missing and non-matching. 16545f02ae47134953169805d281992c9edf0019250Chris Sosa if not actual_attr_val: 1660338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.error('No value found for %s (expected %s)', 1670338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold *self._attr_name_and_values(attr_name, 1680338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold expected_attr_val)[0:2]) 16945f02ae47134953169805d281992c9edf0019250Chris Sosa return False 17045f02ae47134953169805d281992c9edf0019250Chris Sosa 1710338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold # Convert actual value to a string. 17245f02ae47134953169805d281992c9edf0019250Chris Sosa actual_attr_val = str(actual_attr_val) 17345f02ae47134953169805d281992c9edf0019250Chris Sosa 17445f02ae47134953169805d281992c9edf0019250Chris Sosa if not actual_attr_val == expected_attr_val: 1750338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold # We allow expected version numbers (e.g. 2940.0.0) to be contained 1760338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold # in actual values (2940.0.0-a1); this is necessary for the test to 1770338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold # pass with developer / non-release images. 1780338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if 'version' in attr_name and expected_attr_val in actual_attr_val: 1790338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Expected %s (%s) contained in actual value (%s) ' 1800338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'but does not match exactly', 1810338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold *self._attr_name_and_values( 1820338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold attr_name, expected_attr_val, 1830338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual_attr_val=actual_attr_val)) 184fec1349a3e70eb41dce8bc07a8c63563d23d64b2Chris Sosa return True 185fec1349a3e70eb41dce8bc07a8c63563d23d64b2Chris Sosa 1860338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.error('Expected %s (%s) different from actual value (%s)', 1870338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold *self._attr_name_and_values( 1880338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold attr_name, expected_attr_val, 1890338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual_attr_val=actual_attr_val)) 1900ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return False 1910ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1920ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return True 1930ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1940ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1950ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass ExpectedUpdateEventChain(object): 1960ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Defines a chain of expected update events.""" 1970ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __init__(self, *expected_event_chain_args): 1980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Initialize the chain object. 1990ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2000ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param expected_event_chain_args: list of tuples arguments, each 2010ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold containing a timeout (in seconds) and an ExpectedUpdateEvent 2020ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold object. 2030ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2040ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 2050ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._expected_event_chain = expected_event_chain_args 2060ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2070ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 208cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @staticmethod 209cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold def _format_event_with_timeout(timeout, expected_event): 210cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Returns a string representation of the event, with timeout.""" 2110ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return ('%s %s' % 2120ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold (expected_event, 2130ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold ('within %s seconds' % timeout) if timeout 2140ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold else 'indefinitely')) 2150ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2160ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2170ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __str__(self): 2180ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return ('[%s]' % 2190ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold ', '.join( 2200ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold [self._format_event_with_timeout(timeout, expected_event) 2210ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold for timeout, expected_event 2220ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold in self._expected_event_chain])) 2230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2240ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2250ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __repr__(self): 2260ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return str(self._expected_event_chain) 2270ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2280ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2290ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def verify(self, get_next_event): 2300ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies that an actual stream of events complies. 2310ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2320ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param get_next_event: a function returning the next event 2330ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 234ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify an event. 2350ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2360ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 2370ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold for timeout, expected_event in self._expected_event_chain: 2380338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Expecting %s', 239ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._format_event_with_timeout(timeout, 240ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa expected_event)) 2410ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if not self._verify_event_with_timeout( 2420ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold timeout, expected_event, get_next_event): 243ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa logging.error('Failed expected event: %s', 244ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa expected_event.error_message) 245ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa raise ExpectedUpdateEventChainFailed( 246ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa expected_event.error_message) 2470ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2480ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 249cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @staticmethod 250cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold def _verify_event_with_timeout(timeout, expected_event, get_next_event): 2510ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verify an expected event occurs within a given timeout. 2520ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2530ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param timeout: specified in seconds 2540ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param expected_event: an expected event specification 2550ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param get_next_event: function returning the next event in a stream 2560ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2570ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return True if event complies, False otherwise. 2580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 2600ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold base_timestamp = curr_timestamp = time.time() 2610ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold expired_timestamp = base_timestamp + timeout 2620ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold while curr_timestamp <= expired_timestamp: 2630ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold new_event = get_next_event() 2640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if new_event: 2650338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Event received after %s seconds', 2660338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold round(curr_timestamp - base_timestamp, 1)) 2670ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return expected_event.verify(new_event) 2680ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2690ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # No new events, sleep for one second only (so we don't miss 2700ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # events at the end of the allotted timeout). 2710ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold time.sleep(1) 2720ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold curr_timestamp = time.time() 2730ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2740338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.error('Timeout expired') 2750ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return False 2760ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2770ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2780ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass UpdateEventLogVerifier(object): 2790ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies update event chains on a devserver update log.""" 28003901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold def __init__(self, event_log_url, url_request_timeout=None): 2810ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._event_log_url = event_log_url 28203901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold self._url_request_timeout = url_request_timeout 2830ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._event_log = [] 2840ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._num_consumed_events = 0 2850ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2860ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2870ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def verify_expected_event_chain(self, expected_event_chain): 288ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa """Verify a given event chain. 289ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa 290ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa @param expected_event_chain: instance of expected event chain. 291ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 292ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify the an 293ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa event. 294ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa """ 295ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa expected_event_chain.verify(self._get_next_log_event) 2960ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2970ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def _get_next_log_event(self): 2990ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Returns the next event in an event log. 3000ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3010ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold Uses the URL handed to it during initialization to obtain the host log 3020ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold from a devserver. If new events are encountered, the first of them is 3030ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold consumed and returned. 3040ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3050ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return The next new event in the host log, as reported by devserver; 30603901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold None if no such event was found or an error occurred. 3070ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3080ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 3090ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # (Re)read event log from devserver, if necessary. 3100ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if len(self._event_log) <= self._num_consumed_events: 31103901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold try: 31203901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold if self._url_request_timeout: 31303901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold conn = urllib2.urlopen(self._event_log_url, 31403901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold timeout=self._url_request_timeout) 31503901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold else: 31603901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold conn = urllib2.urlopen(self._event_log_url) 31703901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold except urllib2.URLError, e: 3180338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.warning('Failed to read event log url: %s', e) 31903901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold return None 320a0261611f9be78ee9d456fd50bea81e9eda07c17Gilad Arnold except socket.timeout, e: 321a0261611f9be78ee9d456fd50bea81e9eda07c17Gilad Arnold logging.warning('Timed out reading event log url: %s', e) 322a0261611f9be78ee9d456fd50bea81e9eda07c17Gilad Arnold return None 32303901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold 3240ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold event_log_resp = conn.read() 3250ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold conn.close() 3260ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._event_log = json.loads(event_log_resp) 3270ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 32803901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold # Return next new event, if one is found. 3290ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if len(self._event_log) > self._num_consumed_events: 3300ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold new_event = self._event_log[self._num_consumed_events] 3310ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._num_consumed_events += 1 3320338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Consumed new event: %s', new_event) 3330ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return new_event 3340ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3350ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 336793344b359304c31d78197788b55cfbbe2636025Chris Sosaclass OmahaDevserverFailedToStart(error.TestError): 337793344b359304c31d78197788b55cfbbe2636025Chris Sosa """Raised when a omaha devserver fails to start.""" 338793344b359304c31d78197788b55cfbbe2636025Chris Sosa 339793344b359304c31d78197788b55cfbbe2636025Chris Sosa 3400ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass OmahaDevserver(object): 3410ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Spawns a test-private devserver instance.""" 342793344b359304c31d78197788b55cfbbe2636025Chris Sosa # How long to wait for a devserver to start. 3430ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold _WAIT_FOR_DEVSERVER_STARTED_SECONDS = 15 344793344b359304c31d78197788b55cfbbe2636025Chris Sosa 345260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # How long to sleep (seconds) between checks to see if a devserver is up. 34603901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold _WAIT_SLEEP_INTERVAL = 1 3470ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3486f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # Max devserver execution time (seconds); used with timeout(1) to ensure we 3496f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # don't have defunct instances hogging the system. 3506f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold _DEVSERVER_TIMELIMIT_SECONDS = 12 * 60 * 60 351793344b359304c31d78197788b55cfbbe2636025Chris Sosa 352793344b359304c31d78197788b55cfbbe2636025Chris Sosa 353260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def __init__(self, omaha_host, devserver_dir, update_payload_staged_url): 3540ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Starts a private devserver instance, operating at Omaha capacity. 3550ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3560ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param omaha_host: host address where the devserver is spawned. 35703901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold @param devserver_dir: path to the devserver source directory 358ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param update_payload_staged_url: URL to provision for update requests. 3590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3600ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 361ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa if not update_payload_staged_url: 3620338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold raise error.TestError('Missing update payload url') 3630ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3646c55bdb98e967675456a71a0971b81058536cac8Chris Sosa self._omaha_host = omaha_host 365260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid = 0 366260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_port = 0 # Determined later from devserver portfile. 3676c55bdb98e967675456a71a0971b81058536cac8Chris Sosa self._devserver_dir = devserver_dir 368ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._update_payload_staged_url = update_payload_staged_url 3696c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 3706c55bdb98e967675456a71a0971b81058536cac8Chris Sosa self._devserver_ssh = hosts.SSHHost(self._omaha_host, 3716c55bdb98e967675456a71a0971b81058536cac8Chris Sosa user=os.environ['USER']) 372260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 3733563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa # Temporary files for various devserver outputs. 3743563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_logfile = None 3753563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_portfile = None 3763563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_pidfile = None 3773563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_static_dir = None 3783563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 3793563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 3803563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa def _cleanup_devserver_files(self): 3813563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa """Cleans up the temporary devserver files.""" 3823563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa for filename in (self._devserver_logfile, self._devserver_portfile, 3833563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_pidfile): 3843563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa if filename: 3853563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_ssh.run('rm -f %s' % filename, ignore_status=True) 3863563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 3873563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa if self._devserver_static_dir: 3883563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_ssh.run('rm -rf %s' % self._devserver_static_dir, 3893563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa ignore_status=True) 3903563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 391260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 3923563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa def _create_tempfile_on_devserver(self, label, dir=False): 3933563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa """Creates a temporary file/dir on the devserver and returns its path. 394260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 395260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @param label: Identifier for the file context (string, no whitespaces). 3963563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa @param dir: If True, create a directory instead of a file. 397260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 398260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @raises test.TestError: If we failed to invoke mktemp on the server. 399260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @raises OmahaDevserverFailedToStart: If tempfile creation failed. 400260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """ 401260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold remote_cmd = 'mktemp --tmpdir devserver-%s.XXXXXX' % label 4023563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa if dir: 4033563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa remote_cmd += ' --directory' 4043563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 405260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 406260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold result = self._devserver_ssh.run(remote_cmd, ignore_status=True) 407260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except error.AutoservRunError as e: 408260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._log_and_raise_remote_ssh_error(e) 409260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if result.exit_status != 0: 410260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold raise OmahaDevserverFailedToStart( 411260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'Could not create a temporary %s file on the devserver, ' 412260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'error output:\n%s' % (label, result.stderr)) 413260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return result.stdout.strip() 414260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 415260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @staticmethod 416260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _log_and_raise_remote_ssh_error(e): 417260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Logs failure to ssh remote, then raises a TestError.""" 418260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.debug('Failed to ssh into the devserver: %s', e) 419260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.error('If you are running this locally it means you did not ' 420260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'configure ssh correctly.') 421260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold raise error.TestError('Failed to ssh into the devserver: %s' % e) 422260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 423260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 424260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _read_int_from_devserver_file(self, filename): 425260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Reads and returns an integer value from a file on the devserver.""" 426260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return int(self._get_devserver_file_content(filename).strip()) 4270ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 4286c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 429793344b359304c31d78197788b55cfbbe2636025Chris Sosa def _wait_for_devserver_to_start(self): 430793344b359304c31d78197788b55cfbbe2636025Chris Sosa """Waits until the devserver starts within the time limit. 431793344b359304c31d78197788b55cfbbe2636025Chris Sosa 432260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold Infers and sets the devserver PID and serving port. 433260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 434793344b359304c31d78197788b55cfbbe2636025Chris Sosa Raises: 435793344b359304c31d78197788b55cfbbe2636025Chris Sosa OmahaDevserverFailedToStart: If the time limit is reached and we 436793344b359304c31d78197788b55cfbbe2636025Chris Sosa cannot connect to the devserver. 437793344b359304c31d78197788b55cfbbe2636025Chris Sosa """ 438260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # Compute the overall timeout. 439260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold deadline = time.time() + self._WAIT_FOR_DEVSERVER_STARTED_SECONDS 440260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 441260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # First, wait for port file to be filled and determine the server port. 44294b9ad4983cc735e162a3549c1628d08241b0d57Gilad Arnold logging.warning('Waiting for devserver to start up.') 443260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold while time.time() < deadline: 444260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 445260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid = self._read_int_from_devserver_file( 446260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pidfile) 447260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_port = self._read_int_from_devserver_file( 448260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_portfile) 449260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.info('Devserver pid is %d, serving on port %d', 450260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid, self._devserver_port) 451260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold break 452260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except Exception: # Couldn't read file or corrupt content. 453260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold time.sleep(self._WAIT_SLEEP_INTERVAL) 454260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold else: 45594b9ad4983cc735e162a3549c1628d08241b0d57Gilad Arnold raise OmahaDevserverFailedToStart( 456260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'The test failed to find the pid/port of the omaha ' 457260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'devserver. Check the dumped devserver logs for more ' 458260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'information.') 459260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 460260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # Check that the server is reponsding to network requests. 461260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.warning('Waiting for devserver to accept network requests.') 462260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold url = 'http://%s' % self.get_netloc() 463260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold while time.time() < deadline: 464260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if dev_server.DevServer.devserver_healthy(url, timeout_min=0.1): 465260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold break 466793344b359304c31d78197788b55cfbbe2636025Chris Sosa 467793344b359304c31d78197788b55cfbbe2636025Chris Sosa # TODO(milleral): Refactor once crbug.com/221626 is resolved. 468793344b359304c31d78197788b55cfbbe2636025Chris Sosa time.sleep(self._WAIT_SLEEP_INTERVAL) 469793344b359304c31d78197788b55cfbbe2636025Chris Sosa else: 470793344b359304c31d78197788b55cfbbe2636025Chris Sosa raise OmahaDevserverFailedToStart( 471793344b359304c31d78197788b55cfbbe2636025Chris Sosa 'The test failed to establish a connection to the omaha ' 472793344b359304c31d78197788b55cfbbe2636025Chris Sosa 'devserver it set up on port %d. Check the dumped ' 473260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'devserver logs for more information.' % 474260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_port) 475793344b359304c31d78197788b55cfbbe2636025Chris Sosa 476793344b359304c31d78197788b55cfbbe2636025Chris Sosa 4776c55bdb98e967675456a71a0971b81058536cac8Chris Sosa def start_devserver(self): 478793344b359304c31d78197788b55cfbbe2636025Chris Sosa """Starts the devserver and confirms it is up. 479793344b359304c31d78197788b55cfbbe2636025Chris Sosa 480793344b359304c31d78197788b55cfbbe2636025Chris Sosa Raises: 481260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold test.TestError: If we failed to spawn the remote devserver. 482793344b359304c31d78197788b55cfbbe2636025Chris Sosa OmahaDevserverFailedToStart: If the time limit is reached and we 483793344b359304c31d78197788b55cfbbe2636025Chris Sosa cannot connect to the devserver. 4846c55bdb98e967675456a71a0971b81058536cac8Chris Sosa """ 4852f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa update_payload_url_base, update_payload_path = self._split_url( 486ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._update_payload_staged_url) 4873563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 4883563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa # Allocate temporary files for various server outputs. 4893563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_logfile = self._create_tempfile_on_devserver('log') 4903563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_portfile = self._create_tempfile_on_devserver('port') 4913563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_pidfile = self._create_tempfile_on_devserver('pid') 4923563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_static_dir = self._create_tempfile_on_devserver( 4933563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 'static', dir=True) 4943563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 4956f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # Invoke the Omaha/devserver on the remote server. Will attempt to kill 4966f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # it with a SIGTERM after a predetermined timeout has elapsed, followed 4976f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # by SIGKILL if not dead within 30 seconds from the former signal. 4980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold cmdlist = [ 4996f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold 'timeout', '-s', 'TERM', '-k', '30', 5006f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold str(self._DEVSERVER_TIMELIMIT_SECONDS), 5016c55bdb98e967675456a71a0971b81058536cac8Chris Sosa '%s/devserver.py' % self._devserver_dir, 5020ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--payload=%s' % update_payload_path, 503260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--port=0', 504260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--pidfile=%s' % self._devserver_pidfile, 505260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--portfile=%s' % self._devserver_portfile, 506260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--logfile=%s' % self._devserver_logfile, 5070ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--remote_payload', 5080ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--urlbase=%s' % update_payload_url_base, 5090ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--max_updates=1', 5100ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--host_log', 5113563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa '--static_dir=%s' % self._devserver_static_dir, 5120ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold ] 513260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold remote_cmd = '( %s ) </dev/null >/dev/null 2>&1 &' % ' '.join(cmdlist) 5146c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 515260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.info('Starting devserver with %r', remote_cmd) 516260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 517260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_ssh.run_output(remote_cmd) 518260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except error.AutoservRunError as e: 519260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._log_and_raise_remote_ssh_error(e) 5206c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 521260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 522260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._wait_for_devserver_to_start() 523260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except OmahaDevserverFailedToStart: 524260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._kill_remote_process() 525260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._dump_devserver_log() 5263563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._cleanup_devserver_file() 527260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold raise 52838ba6b79b19b5bdd9cfe71b26efd0c267768527aGilad Arnold 5296c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 530260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _kill_remote_process(self): 531260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Kills the devserver and verifies it's down; clears the remote pid.""" 532260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def devserver_down(): 533cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Ensure that the devserver process is down.""" 534260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return not self._remote_process_alive() 5356c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 536260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if devserver_down(): 5376c55bdb98e967675456a71a0971b81058536cac8Chris Sosa return 5386c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 539260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold for signal in 'SIGTERM', 'SIGKILL': 540260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold remote_cmd = 'kill -s %s %s' % (signal, self._devserver_pid) 541260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_ssh.run(remote_cmd) 542260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 543260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold client_utils.poll_for_condition( 544260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold devserver_down, sleep_interval=1, desc='devserver down') 545260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold break 546260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except client_utils.TimeoutError: 547260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.warning('Could not kill devserver with %s.', signal) 548260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold else: 549260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.warning('Failed to kill devserver, giving up.') 550260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 551260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid = None 5526c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 5536c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 554260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _remote_process_alive(self): 555260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Tests whether the remote devserver process is running.""" 556260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if not self._devserver_pid: 557260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return False 558260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold remote_cmd = 'test -e /proc/%s' % self._devserver_pid 559260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold result = self._devserver_ssh.run(remote_cmd, ignore_status=True) 560260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return result.exit_status == 0 5616c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 5626c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 5636c55bdb98e967675456a71a0971b81058536cac8Chris Sosa def get_netloc(self): 5646c55bdb98e967675456a71a0971b81058536cac8Chris Sosa """Returns the netloc (host:port) of the devserver.""" 565260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if not (self._devserver_pid and self._devserver_port): 5660338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold raise error.TestError('No running omaha/devserver') 5676c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 568260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return '%s:%s' % (self._omaha_host, self._devserver_port) 5690ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 5706c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 5712f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa def get_update_url(self): 5722f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Returns the update_url you can use to update via this server.""" 5732f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa return urlparse.urlunsplit(('http', self.get_netloc(), '/update', 5742f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa '', '')) 5752f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 5762f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 577260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _get_devserver_file_content(self, filename): 578260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Returns the content of a file on the devserver.""" 579260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return self._devserver_ssh.run_output('cat %s' % filename) 580260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 581260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 582260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _get_devserver_log(self): 583260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Obtain the devserver output.""" 584260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return self._get_devserver_file_content(self._devserver_logfile) 585260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 586260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 587260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _dump_devserver_log(self, logging_level=logging.ERROR): 5883563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa """Dump the devserver log to the autotest log. 58919426059c61c1b318b5d4bd04d70dacb63ec827dChris Sosa 59019426059c61c1b318b5d4bd04d70dacb63ec827dChris Sosa @param logging_level: logging level (from logging) to log the output. 59119426059c61c1b318b5d4bd04d70dacb63ec827dChris Sosa """ 592260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.log(logging_level, self._get_devserver_log()) 5930ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 5940ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 5950ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @staticmethod 5960ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def _split_url(url): 5972f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Splits a URL into the URL base and path.""" 5980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold split_url = urlparse.urlsplit(url) 5990ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold url_base = urlparse.urlunsplit( 6002f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa (split_url.scheme, split_url.netloc, '', '', '')) 6012f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa url_path = split_url.path 6022f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa return url_base, url_path.lstrip('/') 6030ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6040ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 605260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def stop_devserver(self): 606260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Kill remote process and wait for it to die, dump its output.""" 6076c55bdb98e967675456a71a0971b81058536cac8Chris Sosa if not self._devserver_pid: 608ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa logging.error('No running omaha/devserver.') 609ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa return 6106c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 6110338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Killing omaha/devserver') 612260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._kill_remote_process() 61319426059c61c1b318b5d4bd04d70dacb63ec827dChris Sosa logging.debug('Final devserver log before killing') 614260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._dump_devserver_log(logging.DEBUG) 6153563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._cleanup_devserver_files() 6160ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6170ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6180ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass autoupdate_EndToEndTest(test.test): 6190ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Complete update test between two Chrome OS releases. 6200ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6210ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold Performs an end-to-end test of updating a ChromeOS device from one version 6220ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold to another. This script requires a running (possibly remote) servod 6230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold instance connected to an actual servo board, which controls the DUT. It 6240ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold also assumes that a corresponding target (update) image was staged for 625ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa download on a central staging devserver. 6260ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6270ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold The test performs the following steps: 6280ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6290ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 0. Stages the source image and target update payload on the central 6300ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold Lorry/devserver. 6310ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1. Spawns a private Omaha/devserver instance, configured to return the 6320ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold target (update) image URL in response for an update check. 6330ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2. Connects to servod. 6340ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold a. Resets the DUT to a known initial state. 6350ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold b. Installs a source image on the DUT via recovery. 6360ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3. Reboots the DUT with the new image. 6370ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 4. Triggers an update check at the DUT. 6380ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 5. Watches as the DUT obtains an update and applies it. 6390ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6. Repeats 3-5, ensuring that the next update check shows the new image 6400ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold version. 6410ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 642ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa Some notes on naming: 643ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa devserver: Refers to a machine running the Chrome OS Update Devserver. 644ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver: An autotest wrapper to interact with a devserver. 645ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa Can be used to stage artifacts to a devserver. While 646ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa this can also be used to update a machine, we do not 647ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa use it for that purpose in this test as we manage 648ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa updates with out own devserver instances (see below). 649ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa omaha_devserver: This test's wrapper of a devserver running for the 650ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa purposes of emulating omaha. This test controls the 651ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa lifetime of this devserver instance and is separate 652ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa from the autotest lab's devserver's instances which are 653ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa only used for staging and hosting artifacts (because they 654ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa scale). These are run on the same machines as the actual 655ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest devservers which are used for staging but on 656ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa different ports. 657ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa *staged_url's: In this case staged refers to the fact that these items 658ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa are available to be downloaded statically from these urls 659ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa e.g. 'localhost:8080/static/my_file.gz'. These are usually 660ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa given after staging an artifact using a autotest_devserver 661ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa though they can be re-created given enough assumptions. 662ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa *update_url's: Urls refering to the update RPC on a given omaha devserver. 663ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa Since we always use an instantiated omaha devserver to run 664ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa updates, these will always reference an existing instance 665ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa of an omaha devserver that we just created for the purposes 666ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa of updating. 667ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa devserver_hostname: At the start of each test, we choose a devserver 668ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa machine in the lab for the test. We use the devserver 669ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa instance there (access by autotest_devserver) to stage 670ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa artifacts. However, we also use the same host to start 671ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa omaha devserver instances for updating machines with 672ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa (that reference the staged paylaods on the autotest 673ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa devserver instance). This hostname refers to that 674ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa machine we are using (since it's always the same for 675ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa both staging/omaha'ing). 676ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 6770ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 6780ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold version = 1 6790ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6800ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # Timeout periods, given in seconds. 681f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa _WAIT_AFTER_SHUTDOWN_SECONDS = 10 682f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa _WAIT_AFTER_UPDATE_SECONDS = 20 683f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa _WAIT_FOR_USB_INSTALL_SECONDS = 4 * 60 684f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa _WAIT_FOR_MP_RECOVERY_SECONDS = 8 * 60 6850ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold _WAIT_FOR_INITIAL_UPDATE_CHECK_SECONDS = 12 * 60 6864f4426a2184828ad195fbb0b66b34f809a619236Chris Sosa # TODO(sosa): Investigate why this needs to be so long (this used to be 6874f4426a2184828ad195fbb0b66b34f809a619236Chris Sosa # 120 and regressed). 6884f4426a2184828ad195fbb0b66b34f809a619236Chris Sosa _WAIT_FOR_DOWNLOAD_STARTED_SECONDS = 4 * 60 6896c55bdb98e967675456a71a0971b81058536cac8Chris Sosa _WAIT_FOR_DOWNLOAD_COMPLETED_SECONDS = 10 * 60 690f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa _WAIT_FOR_UPDATE_COMPLETED_SECONDS = 4 * 60 6910ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold _WAIT_FOR_UPDATE_CHECK_AFTER_REBOOT_SECONDS = 15 * 60 69203901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold _DEVSERVER_HOSTLOG_REQUEST_TIMEOUT_SECONDS = 30 6930ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 69415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold _STATEFUL_UPDATE_FILENAME = 'stateful.tgz' 695c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen _LOGINABLE_MINIMUM_RELEASE = 5110 69615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 6972f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # Named tuple containing urls for staged urls needed for test. 6982f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # source_url: url to find the update payload for the source image. 6992f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # source_stateful_url: url to find the stateful payload for the source 7002f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # image. 7012f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # target_url: url to find the update payload for the target image. 7022f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # target_stateful_url: url to find the stateful payload for the target 7032f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # image. 7042f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa _STAGED_URLS = collections.namedtuple( 7052f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 'StagedUrls', 7062f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa ['source_url', 'source_stateful_url', 'target_url', 7072f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 'target_stateful_url']) 7082f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 7090ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 710f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa def _servo_dut_power_up(self): 7110ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Powers up the DUT, optionally simulating a Ctrl-D key press.""" 712f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._host.servo.power_short_press() 713f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._dev_mode: 714f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._host.servo.pass_devmode() 7150ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7160ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 717f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa def _servo_dut_reboot(self, disconnect_usbkey=False): 7180ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Reboots a DUT. 7190ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 720e7bd9369b76e2bbdc230c3c1aeb9afc6e6ec60baVadim Bendebury @param disconnect_usbkey: detach USB flash device from the DUT before 721e7bd9369b76e2bbdc230c3c1aeb9afc6e6ec60baVadim Bendebury powering it back up; this is useful when (for example) a USB 722e7bd9369b76e2bbdc230c3c1aeb9afc6e6ec60baVadim Bendebury booted device need not see the attached USB key after the 723e7bd9369b76e2bbdc230c3c1aeb9afc6e6ec60baVadim Bendebury reboot. 7240ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7250ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @raise error.TestFail if DUT fails to reboot. 7260ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7270ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 7280338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Rebooting dut') 729f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._host.servo.power_long_press() 7300ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold _wait(self._WAIT_AFTER_SHUTDOWN_SECONDS, 'after shutdown') 731e7bd9369b76e2bbdc230c3c1aeb9afc6e6ec60baVadim Bendebury if disconnect_usbkey: 732f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._host.servo.switch_usbkey('host') 733f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 734f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._servo_dut_power_up() 735f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_test_image: 736f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if not self._host.wait_up(timeout=self._host.BOOT_TIMEOUT): 7370ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold raise error.TestFail( 7380338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'DUT %s failed to boot after %d secs' % 739f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa (self._host.ip, self._host.BOOT_TIMEOUT)) 7400ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold else: 741cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold # TODO(garnold) chromium-os:33766: implement waiting for MP-signed 742cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold # images; ideas include waiting for a ping reply, or using a GPIO 743cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold # signal. 744cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold pass 7450ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7460ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 747ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def _install_mp_image(self, staged_image_url): 7480ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Installs an MP-signed recovery image on a DUT. 7490ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 750ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param staged_image_url: URL of the image on a Lorry/devserver 7510ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 7520ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # Flash DUT with source image version, using recovery. 7530338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Installing source mp-signed image via recovery: %s', 754ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa staged_image_url) 755f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._host.servo.install_recovery_image( 756ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa staged_image_url, 7570ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold wait_timeout=self._WAIT_FOR_MP_RECOVERY_SECONDS) 7580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # Reboot the DUT after installation. 760f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._servo_dut_reboot(disconnect_usbkey=True) 7610ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7620ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 763ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def _install_test_image_with_servo(self, staged_image_url): 7640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Installs a test image on a DUT, booted via recovery. 7650ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 766ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param staged_image_url: URL of the image on the devserver 7670ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param is_dev_nmode: whether or not the DUT is in dev mode 7680ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7690ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @raise error.TestFail if DUT cannot boot the test image from USB; 7700ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold AutotestHostRunError if failed to run the install command on the 7710ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold DUT. 7720ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7730ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 7740338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Installing source test image via recovery: %s', 775ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa staged_image_url) 776ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._host.servo.install_recovery_image(staged_image_url) 7770338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Waiting for image to boot') 778f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if not self._host.wait_up(timeout=self._host.USB_BOOT_TIMEOUT): 779cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold raise error.TestFail( 780cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 'DUT %s boot from usb timed out after %d secs' % 781cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold (self._host, self._host.USB_BOOT_TIMEOUT)) 7820338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Installing new image onto ssd') 7830ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold try: 784f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa cmd_result = self._host.run( 7850ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'chromeos-install --yes', 7860ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold timeout=self._WAIT_FOR_USB_INSTALL_SECONDS, 7870ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold stdout_tee=None, stderr_tee=None) 788f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa except error.AutotestHostRunError: 7890ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # Dump stdout (with stderr) to the error log. 7900338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.error('Command failed, stderr:\n' + cmd_result.stderr) 7910ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold raise 7920ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7930ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # Reboot the DUT after installation. 794f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._servo_dut_reboot(disconnect_usbkey=True) 7950ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7960ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7972f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa def _trigger_test_update(self, omaha_devserver): 7980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Trigger an update check on a test image. 7990ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8002f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param omaha_devserver: Instance of OmahaDevserver that will serve the 8012f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa update. 8020ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @raise RootFSUpdateError if anything went wrong. 8030ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8040ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 8052f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa updater = autoupdater.ChromiumOSUpdater( 8062f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa omaha_devserver.get_update_url(), host=self._host) 8070ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold updater.trigger_update() 8080ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8090ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 810f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa def _get_rootdev(self): 81109706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold """Returns the partition device containing the rootfs on a host. 81209706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 81309706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold @return The rootfs partition device (string). 81409706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 81509706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold @raise AutotestHostRunError if command failed to run on host. 81609706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 81709706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold """ 81866d74078caa789f80d4a43c82b61d6016a0cf430Chris Sosa return self._host.run('rootdev -s').stdout.strip() 81909706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 82009706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 821ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def _stage_image(self, autotest_devserver, image_uri): 822ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Stage a Chrome OS image onto a staging devserver. 8230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 824ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param autotest_devserver: instance of client.common_lib.dev_server to 825ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa use to stage the image. 826ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa @param image_uri: The uri of the image. 827ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @return URL of the staged image on the staging devserver. 8280ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8290ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @raise error.TestError if there's a problem with staging. 8300ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8310ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 832f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_test_image: 8330ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # For this call, we just need the URL path up to the image.zip file 8340ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # (exclusive). 8350ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold image_uri_path = urlparse.urlsplit(image_uri).path.partition( 8360ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'image.zip')[0].strip('/') 8370ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold try: 838ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver.stage_artifacts(image_uri_path, 839ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa ['test_image']) 840ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa return autotest_devserver.get_test_image_url(image_uri_path) 8410ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold except dev_server.DevServerException, e: 8420ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold raise error.TestError( 8430338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'Failed to stage source test image: %s' % e) 8440ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold else: 8450ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # TODO(garnold) chromium-os:33766: implement staging of MP-signed 8460ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # images. 8472f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa raise NotImplementedError() 8480ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8490ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 850cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @staticmethod 851cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold def _stage_payload(autotest_devserver, devserver_label, filename, 85272f48be6c3f7e30edc6ff9a785f9c4cb53521af4Don Garrett archive_url=None): 8532f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Stage the given payload onto the devserver. 8540ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8552f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa Works for either a stateful or full/delta test payload. Expects the 8562f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa gs_path or a combo of devserver_label + filename. 8570ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 858ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param autotest_devserver: instance of client.common_lib.dev_server to 859ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa use to reach the devserver instance for this 860ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa build. 8612f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param devserver_label: The build name e.g. x86-mario-release/<version>. 8622f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa If set, assumes default gs archive bucket and 8632f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa requires filename to be specified. 8642f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param filename: In conjunction with devserver_label, if just specifying 8652f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa the devserver label name, this is which file are you 8662f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa downloading. 86715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @param archive_url: An optional GS archive location, if not using the 86815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold devserver's default. 869ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa 8700ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return URL of the staged payload on the server. 8710ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8720ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @raise error.TestError if there's a problem with staging. 8730ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8740ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 8752f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa try: 876ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver.stage_artifacts( 87772f48be6c3f7e30edc6ff9a785f9c4cb53521af4Don Garrett image=devserver_label, files=[filename], 87872f48be6c3f7e30edc6ff9a785f9c4cb53521af4Don Garrett archive_url=archive_url) 879ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa return autotest_devserver.get_staged_file_url(filename, 880ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa devserver_label) 8812f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa except dev_server.DevServerException, e: 8820338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold raise error.TestError('Failed to stage payload: %s' % e) 8830ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8840ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 88572f48be6c3f7e30edc6ff9a785f9c4cb53521af4Don Garrett def _stage_payload_by_uri(self, autotest_devserver, payload_uri): 88615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """Stage a payload based on its GS URI. 88715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 88815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold This infers the build's label, filename and GS archive from the 88915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold provided GS URI. 89015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 89115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @param autotest_devserver: instance of client.common_lib.dev_server to 89215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold use to reach the devserver instance for this 89315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold build. 89415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @param payload_uri: The full GS URI of the payload. 89515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 89615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @return URL of the staged payload on the server. 89715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 89815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @raise error.TestError if there's a problem with staging. 89915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 90015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """ 90115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold archive_url, _, filename = payload_uri.rpartition('/') 90215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold devserver_label = urlparse.urlsplit(archive_url).path.strip('/') 90315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold return self._stage_payload(autotest_devserver, devserver_label, 90472f48be6c3f7e30edc6ff9a785f9c4cb53521af4Don Garrett filename, archive_url=archive_url) 90515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 90615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 907cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @staticmethod 908cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold def _payload_to_update_url(payload_url): 9092f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Given a update or stateful payload url, returns the update url.""" 9107231260da421abdf5ceceff6ab60155936dca21fChris Sosa # We want to transform it to the correct omaha url which is 9117231260da421abdf5ceceff6ab60155936dca21fChris Sosa # <hostname>/update/...LABEL. 9122f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa base_url = payload_url.rpartition('/')[0] 9132f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa return base_url.replace('/static/', '/update/') 9142f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 9152f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 91615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold def _get_stateful_uri(self, build_uri): 91715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """Returns a complete GS URI of a stateful update given a build path.""" 91815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold return '/'.join([build_uri.rstrip('/'), self._STATEFUL_UPDATE_FILENAME]) 91915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 92015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 92115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold def _payload_to_stateful_uri(self, payload_uri): 92215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """Given a payload GS URI, returns the corresponding stateful URI.""" 92315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold build_uri = payload_uri.rpartition('/')[0] 92415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold return self._get_stateful_uri(build_uri) 9252f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 9262f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 9272f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa def update_via_test_payloads(self, omaha_host, payload_url, stateful_url, 9282f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa clobber): 929cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Given the following update and stateful urls, update the DUT. 930cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 931cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold Only updates the rootfs/stateful if the respective url is provided. 932cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 933cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param omaha_host: If updating rootfs, redirect updates through this 934cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold host. Should be None iff payload_url is None. 935cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param payload_url: If set, the specified url to find the update 936cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold payload. 937cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param stateful_url: If set, the specified url to find the stateful 938cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold payload. 939cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param clobber: If True, do a clean install of stateful. 940cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """ 941cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold def perform_update(url, is_stateful): 942cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Perform a rootfs/stateful update using given URL. 943cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 944cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param url: URL to update from. 945cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param is_stateful: Whether this is a stateful or rootfs update. 946cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """ 947cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if url: 948cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold updater = autoupdater.ChromiumOSUpdater(url, host=self._host) 949cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if is_stateful: 950cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold updater.update_stateful(clobber=clobber) 951cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold else: 952cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold updater.update_rootfs() 953cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 954cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold # We create a OmahaDevserver to redirect blah.bin to update/. This 955cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold # allows us to use any payload filename to serve an update. 956cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold temp_devserver = None 957cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold try: 958cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if payload_url: 959cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold temp_devserver = OmahaDevserver( 960260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold omaha_host, self._devserver_dir, payload_url) 961cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold temp_devserver.start_devserver() 962cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold payload_url = temp_devserver.get_update_url() 963cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 964cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold stateful_url = self._payload_to_update_url(stateful_url) 965cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 966cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold perform_update(payload_url, False) 967cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold perform_update(stateful_url, True) 968cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold finally: 969cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if temp_devserver: 970260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold temp_devserver.stop_devserver() 9712f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 9722f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 973ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def install_source_version(self, devserver_hostname, image_url, 974ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa stateful_url): 9752f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Prepare the specified host with the image given by the urls. 9762f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 977ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param devserver_hostname: If updating rootfs, redirect updates 978ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa through this host. Should be None iff 979ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa image_url is None. 9802f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param image_url: If set, the specified url to find the source image 9812f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa or full payload for the source image. 9822f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param stateful_url: If set, the specified url to find the stateful 9832f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa payload. 9842f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """ 985f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_servo: 986f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # Install source image (test vs MP). 987f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_test_image: 988f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._install_test_image_with_servo(image_url) 989f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa else: 990f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._install_mp_image(image_url) 991f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 992f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa else: 99345f02ae47134953169805d281992c9edf0019250Chris Sosa try: 9942f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # Reboot to get us into a clean state. 9952f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa self._host.reboot() 9962f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # Since we are installing the source image of the test, clobber 9972f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # stateful. 998ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self.update_via_test_payloads(devserver_hostname, image_url, 9992f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa stateful_url, clobber=True) 10002f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa self._host.reboot() 100145f02ae47134953169805d281992c9edf0019250Chris Sosa except error.AutoservRunError: 100245f02ae47134953169805d281992c9edf0019250Chris Sosa logging.fatal('Error re-imaging the machine with the source ' 100345f02ae47134953169805d281992c9edf0019250Chris Sosa 'image %s', image_url) 10048577f8fb064fc8392bdc399fdd7465307d6da03bAlex Miller raise error.TestError('Could not update to pre-conditions of ' 10058577f8fb064fc8392bdc399fdd7465307d6da03bAlex Miller 'the test: we failed to start the ' 10068577f8fb064fc8392bdc399fdd7465307d6da03bAlex Miller 'private devserver, connect to the host ' 10078577f8fb064fc8392bdc399fdd7465307d6da03bAlex Miller 'and/or make it reboot.') 1008f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1009f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1010ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def stage_artifacts_onto_devserver(self, autotest_devserver, test_conf): 10112f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Stages artifacts that will be used by the test onto the devserver. 10122f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 1013ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param autotest_devserver: instance of client.common_lib.dev_server to 1014ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa use to reach the devserver instance for this 1015ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa build. 10162f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param test_conf: a dictionary containing test configuration values 10172f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 10182f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @return a _STAGED_URLS tuple containing the staged urls. 1019f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa """ 10200338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Staging images onto autotest devserver (%s)', 1021ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver.url()) 1022f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 102315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold source_image_uri = test_conf['source_image_uri'] 102415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 102515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_source_url = None 102615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold source_stateful_uri = None 102715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_source_stateful_url = None 1028f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_servo: 102915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_source_url = self._stage_image( 103015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold autotest_devserver, source_image_uri) 103115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold # Test image already contains a stateful update, leave 103215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold # staged_source_stateful_url untouhced. 1033f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa else: 103415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_source_url = self._stage_payload_by_uri( 103515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold autotest_devserver, source_image_uri) 103615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 103715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold # In order to properly install the source image using a full 103815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold # payload we'll also need the stateful update that comes with it. 103915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold # In general, tests may have their source artifacts in a different 104015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold # location than their payloads. This is determined by whether or 104115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold # not the source_archive_uri attribute is set; if it isn't set, 104215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold # then we derive it from the dirname of the source payload. 10432f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa source_archive_uri = test_conf.get('source_archive_uri') 104415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold if source_archive_uri: 104515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold source_stateful_uri = self._get_stateful_uri(source_archive_uri) 10462f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa else: 104715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold source_stateful_uri = self._payload_to_stateful_uri( 104815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold source_image_uri) 104915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 105015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_source_stateful_url = self._stage_payload_by_uri( 105115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold autotest_devserver, source_stateful_uri) 105215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 105315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_payload_uri = test_conf['target_payload_uri'] 105415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_url = self._stage_payload_by_uri( 105515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold autotest_devserver, target_payload_uri) 105615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri = None 105715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_archive_uri = test_conf.get('target_archive_uri') 105815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold if not target_archive_uri and self._job_repo_url: 10592f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa _, devserver_label = tools.get_devserver_build_from_package_url( 10602f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa self._job_repo_url) 106115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_stateful_url = self._stage_payload( 106215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold autotest_devserver, devserver_label, 106315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold self._STATEFUL_UPDATE_FILENAME) 10642f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa else: 106515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold if target_archive_uri: 106615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri = self._get_stateful_uri(target_archive_uri) 106715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold else: 106815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri = self._payload_to_stateful_uri( 106915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_payload_uri) 1070f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 107115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_stateful_url = self._stage_payload_by_uri( 107215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold autotest_devserver, target_stateful_uri) 10732f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 107415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold # Log all the urls. 10750338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Source %s from %s staged at %s', 107615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 'image' if self._use_servo else 'full payload', 107715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold source_image_uri, staged_source_url) 107815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold if staged_source_stateful_url: 10790338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Source stateful update from %s staged at %s', 108015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold source_stateful_uri, staged_source_stateful_url) 108115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold logging.info('%s test payload from %s staged at %s', 108215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold test_conf['update_type'], target_payload_uri, 108315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_url) 10840338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Target stateful update from %s staged at %s', 108515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri or 'standard location', 108615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_stateful_url) 108715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 108815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold return self._STAGED_URLS(staged_source_url, staged_source_stateful_url, 108915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_url, staged_target_stateful_url) 1090f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1091f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1092f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa def initialize(self): 1093f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa """Sets up variables that will be used by test.""" 1094f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._host = None 1095f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._use_servo = False 1096f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._dev_mode = False 1097f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._omaha_devserver = None 1098f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1099f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._use_test_image = True 11002f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa self._job_repo_url = None 1101f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._devserver_dir = global_config.global_config.get_config_value( 1102f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 'CROS', 'devserver_dir', default=None) 1103f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._devserver_dir is None: 1104f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa raise error.TestError( 11050338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'Path to devserver source tree not provided; please define ' 1106f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 'devserver_dir under [CROS] in your shadow_config.ini') 1107f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1108f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1109f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa def cleanup(self): 1110f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa """Kill the omaha devserver if it's still around.""" 1111f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._omaha_devserver: 1112260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._omaha_devserver.stop_devserver() 1113f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1114f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._omaha_devserver = None 1115f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1116f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 111745f02ae47134953169805d281992c9edf0019250Chris Sosa def _verify_preconditions(self): 1118f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa """Validate input args make sense.""" 1119f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_servo and not self._host.servo: 1120f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa raise error.AutotestError('Servo use specified but no servo ' 1121f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 'attached to host object.') 1122f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1123f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if not self._use_test_image and not self._use_servo: 11240338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold raise error.TestError('Cannot install mp image without servo.') 1125f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1126f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1127c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen def _run_login_test(self, release_string): 1128c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen """Runs login_LoginSuccess test if it is supported by the release.""" 1129c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # Only do login tests with recent builds, since they depend on 1130c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # some binary compatibility with the build itself. 1131c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # '5116.0.0' -> ('5116', '0', '0') -> 5116 1132c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen if int(release_string.split('.')[0]) > self._LOGINABLE_MINIMUM_RELEASE: 1133c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # Login, to prove we can before/after the update. 1134c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen logging.info('Attempting to login (release %s).', release_string) 1135c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1136c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen client_at = autotest.Autotest(self._host) 1137c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen client_at.run_test('login_LoginSuccess') 1138c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen else: 1139c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen logging.info('Not attempting login test because %s is older than ' 1140c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen '%d.', release_string, self._LOGINABLE_MINIMUM_RELEASE) 1141c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1142c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1143ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def _dump_update_engine_log(self): 1144ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Dumps relevant AU error log.""" 114545f02ae47134953169805d281992c9edf0019250Chris Sosa if not self._use_servo: 114645f02ae47134953169805d281992c9edf0019250Chris Sosa logging.error('Test failed -- dumping snippet of update_engine log') 1147ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa try: 1148ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa error_log = self._host.run_output( 1149ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 'tail -n 40 /var/log/update_engine.log') 1150ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa logging.error(error_log) 1151ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa except Exception: 1152ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # Mute any exceptions we get printing debug logs. 1153ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa pass 115445f02ae47134953169805d281992c9edf0019250Chris Sosa 11550ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1156ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def run_update_test(self, staged_urls, test_conf): 1157ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Runs the actual update test once preconditions are met. 11580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1159ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param staged_urls: A _STAGED_URLS tuple containing the staged urls. 1160ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param test_conf: A dictionary containing test configuration values 11610ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1162ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify an update 1163ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa event. 11640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 1165c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1166f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # On test images, record the active root partition. 1167f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa source_rootfs_partition = None 1168f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_test_image: 1169f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa source_rootfs_partition = self._get_rootdev() 11700338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Source image rootfs partition: %s', 1171f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa source_rootfs_partition) 11720ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 11738ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi # Trigger an update. 11748ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi if self._use_test_image: 11758ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi self._trigger_test_update(self._omaha_devserver) 11768ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi else: 11778ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi # TODO(garnold) chromium-os:33766: use GPIOs to trigger an 11788ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi # update. 11798ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi pass 11800ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 11818ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi # Track update progress. 11828ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi omaha_netloc = self._omaha_devserver.get_netloc() 11838ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi omaha_hostlog_url = urlparse.urlunsplit( 11848ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi ['http', omaha_netloc, '/api/hostlog', 11858ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 'ip=' + self._host.ip, '']) 11868ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi logging.info('Polling update progress from omaha/devserver: %s', 11878ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi omaha_hostlog_url) 11888ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi log_verifier = UpdateEventLogVerifier( 11898ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi omaha_hostlog_url, 11908ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi self._DEVSERVER_HOSTLOG_REQUEST_TIMEOUT_SECONDS) 11918ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 11928ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi # Verify chain of events in a successful update process. 11938ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi chain = ExpectedUpdateEventChain( 11948ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi (self._WAIT_FOR_INITIAL_UPDATE_CHECK_SECONDS, 11958ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi ExpectedUpdateEvent( 11968ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi version=test_conf['source_release'], 11978ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi error_message=('Failed to receive initial update check. ' 11988ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 'Check Omaha devserver log in this ' 11998ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 'output.'))), 12008ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi (self._WAIT_FOR_DOWNLOAD_STARTED_SECONDS, 12018ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi ExpectedUpdateEvent( 12028ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi event_type=EVENT_TYPE_DOWNLOAD_STARTED, 12038ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi event_result=EVENT_RESULT_SUCCESS, 12048ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi version=test_conf['source_release'], 12058ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi error_message=( 12068ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 'Failed to start the download of the update ' 12078ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 'payload from the staging server. Check both the ' 12088ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 'omaha log and update_engine.log in sysinfo (or ' 12098ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 'on the DUT).'))), 12108ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi (self._WAIT_FOR_DOWNLOAD_COMPLETED_SECONDS, 12118ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi ExpectedUpdateEvent( 12128ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi event_type=EVENT_TYPE_DOWNLOAD_FINISHED, 12138ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi event_result=EVENT_RESULT_SUCCESS, 12148ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi version=test_conf['source_release'], 12158ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi error_message=( 12168ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 'Failed to finish download from devserver. Check ' 12178ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 'the update_engine.log in sysinfo (or on the ' 12188ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 'DUT).'))), 12198ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi (self._WAIT_FOR_UPDATE_COMPLETED_SECONDS, 12208ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi ExpectedUpdateEvent( 12218ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi event_type=EVENT_TYPE_UPDATE_COMPLETE, 12228ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi event_result=EVENT_RESULT_SUCCESS, 12238ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi version=test_conf['source_release'], 12248ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi error_message=( 12258ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 'Failed to complete update before reboot. Check ' 12268ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 'the update_engine.log in sysinfo (or on the ' 12278ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 'DUT).')))) 12288ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 12298ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi log_verifier.verify_expected_event_chain(chain) 12308ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi 12318ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi # Wait after an update completion (safety margin). 12328ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basi _wait(self._WAIT_AFTER_UPDATE_SECONDS, 'after update completion') 1233f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1234f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # Reboot the DUT after the update. 1235ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa if self._use_servo: 1236f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._servo_dut_reboot() 1237f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa else: 12382f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # Only update the stateful partition since the test has updated the 12392f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # rootfs. 12402f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa self.update_via_test_payloads( 12412f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa None, None, staged_urls.target_stateful_url, clobber=False) 1242f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa self._host.reboot() 12430ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1244f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # Trigger a second update check (again, test vs MP). 1245f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_test_image: 12462f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa self._trigger_test_update(self._omaha_devserver) 1247f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa else: 1248f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # TODO(garnold) chromium-os:33766: use GPIOs to trigger an 1249f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # update. 1250f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa pass 12510ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1252f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # Observe post-reboot update check, which should indicate that the 1253f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # image version has been updated. 1254f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa chain = ExpectedUpdateEventChain( 1255f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa (self._WAIT_FOR_UPDATE_CHECK_AFTER_REBOOT_SECONDS, 1256f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa ExpectedUpdateEvent( 12570338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold event_type=EVENT_TYPE_UPDATE_COMPLETE, 12580338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold event_result=EVENT_RESULT_SUCCESS_REBOOT, 1259f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa version=test_conf['target_release'], 1260ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa previous_version=test_conf['source_release'], 12610338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold error_message=( 12620338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'Failed to reboot into the target version after ' 12630338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'an update. Check the sysinfo logs. This probably ' 12640338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'means that the updated image failed to verify ' 12650338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'after reboot and might mean that the update ' 12660338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'payload is bad')))) 1267ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1268ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa log_verifier.verify_expected_event_chain(chain) 1269f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1270f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # On test images, make sure we're using a different partition after 1271f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # the update. 1272f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if self._use_test_image: 1273f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa target_rootfs_partition = self._get_rootdev() 1274f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa if target_rootfs_partition == source_rootfs_partition: 1275f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa raise error.TestFail( 12760338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'Rootfs partition did not change (%s)' % 1277f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa target_rootfs_partition) 12780ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 12790338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info( 12800338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 'Target image rootfs partition changed as expected: %s', 12810338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold target_rootfs_partition) 12820338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 12830338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Update successful, test completed') 12840ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1285ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1286ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa def run_once(self, host, test_conf, use_servo): 1287ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Performs a complete auto update test. 1288ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1289ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param host: a host object representing the DUT 1290ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param test_conf: a dictionary containing test configuration values 1291ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param use_servo: True whether we should use servo. 1292ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1293ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raise error.TestError if anything went wrong with setting up the test; 1294ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa error.TestFail if any part of the test has failed. 1295ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1296ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """ 1297f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 1298f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett if not test_conf['target_release']: 1299f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett raise RequiredArgumentMissing( 1300f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 'target_release is a required argument.') 1301f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 1302ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # Attempt to get the job_repo_url to find the stateful payload for the 1303ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # target image. 1304ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa try: 1305ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._job_repo_url = host.lookup_job_repo_url() 1306ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa except KeyError: 1307ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa logging.warning('Job Repo URL not found. Assuming stateful ' 1308ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 'payload can be found along with the target update') 1309ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1310ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._host = host 1311ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._use_test_image = test_conf.get('image_type') != 'mp' 1312ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._use_servo = use_servo 1313ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa if self._use_servo: 1314ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._dev_mode = self._host.servo.get('dev_mode') == 'on' 1315ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1316ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # Verify that our arguments are sane. 1317ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._verify_preconditions() 1318ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1319ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # Find a devserver to use. We use the payload URI as argument for the 1320ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # lab's devserver load-balancing mechanism. 1321ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver = dev_server.ImageServer.resolve( 1322ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa test_conf['target_payload_uri']) 1323ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa devserver_hostname = urlparse.urlparse( 1324ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver.url()).hostname 1325ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1326ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # Stage source images and update payloads onto a devserver. 1327ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa staged_urls = self.stage_artifacts_onto_devserver( 1328ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver, test_conf) 1329ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1330ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # Install the source version onto the DUT. 1331ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self.install_source_version(devserver_hostname, 1332ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa staged_urls.source_url, 1333ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa staged_urls.source_stateful_url) 1334ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1335ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._omaha_devserver = OmahaDevserver( 1336260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold devserver_hostname, self._devserver_dir, staged_urls.target_url) 1337ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._omaha_devserver.start_devserver() 1338c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1339c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # Make sure we can login before the update. 1340c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen self._run_login_test(test_conf['source_release']) 1341c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1342ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa try: 1343ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self.run_update_test(staged_urls, test_conf) 1344ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa except ExpectedUpdateEventChainFailed: 1345ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._dump_update_engine_log() 1346ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa raise 1347f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 1348c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # And make sure we can login after update. 1349c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen self._run_login_test(test_conf['target_release']) 1350