autoupdate_EndToEndTest.py revision 585cbd6a5cc32db99c6745aa4333471b6b095b43
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 17b9d7adf07aec05db6a3f1a8b74f45abd7a87c74aPrathmesh Prabhufrom autotest_lib.server import afe_utils, 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 330f27cafd72cd7c6aee752d0ec90de1b58e3b97ddGilad Arnoldclass RequiredArgumentMissing(error.TestError): 340f27cafd72cd7c6aee752d0ec90de1b58e3b97ddGilad Arnold """Raised if the test is missing a required argument.""" 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' 43fac9a5d238337da91939328386c2fa4fdfb6d957Alex DeymoEVENT_TYPE_REBOOTED_AFTER_UPDATE = '54' 440338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 450338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold# Update event results. 460338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_ERROR = '0' 470338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_SUCCESS = '1' 480338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_SUCCESS_REBOOT = '2' 490338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_UPDATE_DEFERRED = '9' 500338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 51a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold# Omaha event types/results, from update_engine/omaha_request_action.h 52a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold# These are stored in dict form in order to easily print out the keys. 53a0ca5707ed10a6575ed290f341294331455f7769Gilad ArnoldEVENT_TYPE_DICT = { 54a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_TYPE_DOWNLOAD_COMPLETE: 'download_complete', 55a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_TYPE_INSTALL_COMPLETE: 'install_complete', 56a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_TYPE_UPDATE_COMPLETE: 'update_complete', 57a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_TYPE_DOWNLOAD_STARTED: 'download_started', 58fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo EVENT_TYPE_DOWNLOAD_FINISHED: 'download_finished', 59fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo EVENT_TYPE_REBOOTED_AFTER_UPDATE: 'rebooted_after_update' 60a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold} 61a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 62a0ca5707ed10a6575ed290f341294331455f7769Gilad ArnoldEVENT_RESULT_DICT = { 63a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_RESULT_ERROR: 'error', 64a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_RESULT_SUCCESS: 'success', 65a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_RESULT_SUCCESS_REBOOT: 'success_reboot', 66a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_RESULT_UPDATE_DEFERRED: 'update_deferred' 67a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold} 68a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 690338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 70fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnolddef snippet(text): 71fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold """Returns the text with start/end snip markers around it. 72fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 73fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold @param text: The snippet text. 74fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 75fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold @return The text with start/end snip markers around it. 76fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold """ 77fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold snip = '---8<---' * 10 78fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold start = '-- START -' 79fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold end = '-- END -' 80fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold return ('%s%s\n%s\n%s%s' % 81fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold (start, snip[len(start):], text, end, snip[len(end):])) 82fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 83fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 840ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass ExpectedUpdateEvent(object): 85248108c1c925791d926105f42212b1033213a4dcGilad Arnold """Defines an expected event in an update process.""" 8645f02ae47134953169805d281992c9edf0019250Chris Sosa 870338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold _ATTR_NAME_DICT_MAP = { 88a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'event_type': EVENT_TYPE_DICT, 89a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'event_result': EVENT_RESULT_DICT, 900338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold } 910338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 92a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold _VALID_TYPES = set(EVENT_TYPE_DICT.keys()) 93a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold _VALID_RESULTS = set(EVENT_RESULT_DICT.keys()) 9445f02ae47134953169805d281992c9edf0019250Chris Sosa 950ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __init__(self, event_type=None, event_result=None, version=None, 96248108c1c925791d926105f42212b1033213a4dcGilad Arnold previous_version=None, on_error=None): 97248108c1c925791d926105f42212b1033213a4dcGilad Arnold """Initializes an event expectation. 98248108c1c925791d926105f42212b1033213a4dcGilad Arnold 99248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param event_type: Expected event type. 100248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param event_result: Expected event result code. 101248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param version: Expected reported image version. 102248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param previous_version: Expected reported previous image version. 103248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param on_error: This is either an object to be returned when a received 104248108c1c925791d926105f42212b1033213a4dcGilad Arnold event mismatches the expectation, or a callable used 105248108c1c925791d926105f42212b1033213a4dcGilad Arnold for generating one. In the latter case, takes as 106248108c1c925791d926105f42212b1033213a4dcGilad Arnold input two attribute dictionaries (expected and actual) 107248108c1c925791d926105f42212b1033213a4dcGilad Arnold and an iterable of mismatched keys. If None, a generic 108248108c1c925791d926105f42212b1033213a4dcGilad Arnold message is returned. 109248108c1c925791d926105f42212b1033213a4dcGilad Arnold """ 1100338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if event_type and event_type not in self._VALID_TYPES: 11145f02ae47134953169805d281992c9edf0019250Chris Sosa raise ValueError('event_type %s is not valid.' % event_type) 11245f02ae47134953169805d281992c9edf0019250Chris Sosa 1130338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if event_result and event_result not in self._VALID_RESULTS: 11445f02ae47134953169805d281992c9edf0019250Chris Sosa raise ValueError('event_result %s is not valid.' % event_result) 11545f02ae47134953169805d281992c9edf0019250Chris Sosa 1160ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._expected_attrs = { 1170ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'event_type': event_type, 1180ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'event_result': event_result, 1190ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'version': version, 1200ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'previous_version': previous_version, 1210ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold } 122248108c1c925791d926105f42212b1033213a4dcGilad Arnold self._on_error = on_error 1230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1240ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1250338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold @staticmethod 1260338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold def _attr_val_str(attr_val, helper_dict, default=None): 1270338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """Returns an enriched attribute value string, or default.""" 1280338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if not attr_val: 1290338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return default 1300338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1310338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold s = str(attr_val) 1320338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if helper_dict: 1330338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold s += ':%s' % helper_dict.get(attr_val, 'unknown') 1340338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1350338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return s 1360338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1370338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1380338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold def _attr_name_and_values(self, attr_name, expected_attr_val, 1390338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual_attr_val=None): 1400338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """Returns an attribute name, expected and actual value strings. 1410338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1420338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold This will return (name, expected, actual); the returned value for 1430338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual will be None if its respective input is None/empty. 1440338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1450338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """ 1460338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold helper_dict = self._ATTR_NAME_DICT_MAP.get(attr_name) 1470338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold expected_attr_val_str = self._attr_val_str(expected_attr_val, 1480338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold helper_dict, 1490338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold default='any') 1500338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual_attr_val_str = self._attr_val_str(actual_attr_val, helper_dict) 1510338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1520338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return attr_name, expected_attr_val_str, actual_attr_val_str 1530338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1540338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 155248108c1c925791d926105f42212b1033213a4dcGilad Arnold def _attrs_to_str(self, attrs_dict): 1560338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return ' '.join(['%s=%s' % 1570338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold self._attr_name_and_values(attr_name, attr_val)[0:2] 158248108c1c925791d926105f42212b1033213a4dcGilad Arnold for attr_name, attr_val in attrs_dict.iteritems()]) 159248108c1c925791d926105f42212b1033213a4dcGilad Arnold 160248108c1c925791d926105f42212b1033213a4dcGilad Arnold 161248108c1c925791d926105f42212b1033213a4dcGilad Arnold def __str__(self): 162248108c1c925791d926105f42212b1033213a4dcGilad Arnold return self._attrs_to_str(self._expected_attrs) 1630ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1650ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def verify(self, actual_event): 1660ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verify the attributes of an actual event. 1670ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 168ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa @param actual_event: a dictionary containing event attributes 1690ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 170248108c1c925791d926105f42212b1033213a4dcGilad Arnold @return An error message, or None if all attributes as expected. 1710ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1720ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 173248108c1c925791d926105f42212b1033213a4dcGilad Arnold mismatched_attrs = [ 174248108c1c925791d926105f42212b1033213a4dcGilad Arnold attr_name for attr_name, expected_attr_val 175248108c1c925791d926105f42212b1033213a4dcGilad Arnold in self._expected_attrs.iteritems() 176248108c1c925791d926105f42212b1033213a4dcGilad Arnold if (expected_attr_val and 177248108c1c925791d926105f42212b1033213a4dcGilad Arnold not self._verify_attr(attr_name, expected_attr_val, 178248108c1c925791d926105f42212b1033213a4dcGilad Arnold actual_event.get(attr_name)))] 179248108c1c925791d926105f42212b1033213a4dcGilad Arnold if not mismatched_attrs: 180248108c1c925791d926105f42212b1033213a4dcGilad Arnold return None 181248108c1c925791d926105f42212b1033213a4dcGilad Arnold if callable(self._on_error): 182248108c1c925791d926105f42212b1033213a4dcGilad Arnold return self._on_error(self._expected_attrs, actual_event, 183248108c1c925791d926105f42212b1033213a4dcGilad Arnold mismatched_attrs) 184248108c1c925791d926105f42212b1033213a4dcGilad Arnold if self._on_error is None: 185248108c1c925791d926105f42212b1033213a4dcGilad Arnold return ('Received event (%s) does not match expectation (%s)' % 186248108c1c925791d926105f42212b1033213a4dcGilad Arnold (self._attrs_to_str(actual_event), self)) 187248108c1c925791d926105f42212b1033213a4dcGilad Arnold return self._on_error 1880ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1890ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1900ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def _verify_attr(self, attr_name, expected_attr_val, actual_attr_val): 1910ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies that an actual log event attributes matches expected on. 1920ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1930ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param attr_name: name of the attribute to verify 1940ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param expected_attr_val: expected attribute value 1950ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param actual_attr_val: actual attribute value 1960ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1970ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return True if actual value is present and matches, False otherwise. 1980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1990ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 20045f02ae47134953169805d281992c9edf0019250Chris Sosa # None values are assumed to be missing and non-matching. 201f014ab424450fd595c347d905ac06ccf3d6faaddGilad Arnold if actual_attr_val is None: 2020338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.error('No value found for %s (expected %s)', 2030338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold *self._attr_name_and_values(attr_name, 2040338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold expected_attr_val)[0:2]) 20545f02ae47134953169805d281992c9edf0019250Chris Sosa return False 20645f02ae47134953169805d281992c9edf0019250Chris Sosa 20716e76893c34739649a751f42b3881b57620d665cGilad Arnold # We allow expected version numbers (e.g. 2940.0.0) to be contained in 20816e76893c34739649a751f42b3881b57620d665cGilad Arnold # actual values (2940.0.0-a1); this is necessary for the test to pass 20916e76893c34739649a751f42b3881b57620d665cGilad Arnold # with developer / non-release images. 21016e76893c34739649a751f42b3881b57620d665cGilad Arnold if (actual_attr_val == expected_attr_val or 21116e76893c34739649a751f42b3881b57620d665cGilad Arnold ('version' in attr_name and expected_attr_val in actual_attr_val)): 21216e76893c34739649a751f42b3881b57620d665cGilad Arnold return True 2130ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 21416e76893c34739649a751f42b3881b57620d665cGilad Arnold return False 2150ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2160ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 217248108c1c925791d926105f42212b1033213a4dcGilad Arnold def get_attrs(self): 218248108c1c925791d926105f42212b1033213a4dcGilad Arnold """Returns a dictionary of expected attributes.""" 219248108c1c925791d926105f42212b1033213a4dcGilad Arnold return dict(self._expected_attrs) 220248108c1c925791d926105f42212b1033213a4dcGilad Arnold 221248108c1c925791d926105f42212b1033213a4dcGilad Arnold 2220ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass ExpectedUpdateEventChain(object): 2230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Defines a chain of expected update events.""" 224248108c1c925791d926105f42212b1033213a4dcGilad Arnold def __init__(self): 225fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo self._expected_events_chain = [] 2260ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2270ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 228fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo def add_event(self, expected_events, timeout, on_timeout=None): 229248108c1c925791d926105f42212b1033213a4dcGilad Arnold """Adds an expected event to the chain. 230248108c1c925791d926105f42212b1033213a4dcGilad Arnold 231fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo @param expected_events: The ExpectedEvent, or a list thereof, to wait 232fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo for. If a list is passed, it will wait for *any* 233fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo of the provided events, but only one of those. 234248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param timeout: A timeout (in seconds) to wait for the event. 235248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param on_timeout: An error string to use if the event times out. If 236248108c1c925791d926105f42212b1033213a4dcGilad Arnold None, a generic message is used. 2370ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 238fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo if isinstance(expected_events, ExpectedUpdateEvent): 23916e76893c34739649a751f42b3881b57620d665cGilad Arnold expected_events = [expected_events] 240fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo self._expected_events_chain.append( 241fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo (expected_events, timeout, on_timeout)) 2420ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2430ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 244cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @staticmethod 245fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo def _format_event_with_timeout(expected_events, timeout): 246cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Returns a string representation of the event, with timeout.""" 247248108c1c925791d926105f42212b1033213a4dcGilad Arnold until = 'within %s seconds' % timeout if timeout else 'indefinitely' 248fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo return '%s, %s' % (' OR '.join(map(str, expected_events)), until) 2490ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2500ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2510ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __str__(self): 2520ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return ('[%s]' % 2530ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold ', '.join( 254fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo [self._format_event_with_timeout(expected_events, timeout) 255fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo for expected_events, timeout, _ 256fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo in self._expected_events_chain])) 2570ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __repr__(self): 260fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo return str(self._expected_events_chain) 2610ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2620ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2630ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def verify(self, get_next_event): 2640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies that an actual stream of events complies. 2650ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2660ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param get_next_event: a function returning the next event 2670ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 268ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify an event. 2690ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2700ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 271fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo for expected_events, timeout, on_timeout in self._expected_events_chain: 2720338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Expecting %s', 273fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo self._format_event_with_timeout(expected_events, 274248108c1c925791d926105f42212b1033213a4dcGilad Arnold timeout)) 275248108c1c925791d926105f42212b1033213a4dcGilad Arnold err_msg = self._verify_event_with_timeout( 276fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo expected_events, timeout, on_timeout, get_next_event) 277248108c1c925791d926105f42212b1033213a4dcGilad Arnold if err_msg is not None: 278248108c1c925791d926105f42212b1033213a4dcGilad Arnold logging.error('Failed expected event: %s', err_msg) 279248108c1c925791d926105f42212b1033213a4dcGilad Arnold raise ExpectedUpdateEventChainFailed(err_msg) 2800ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2810ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 282cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @staticmethod 283fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo def _verify_event_with_timeout(expected_events, timeout, on_timeout, 284248108c1c925791d926105f42212b1033213a4dcGilad Arnold get_next_event): 2850ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verify an expected event occurs within a given timeout. 2860ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 287fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo @param expected_events: the list of possible events expected next 288248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param timeout: specified in seconds 289248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param on_timeout: A string to return if timeout occurs, or None. 2900ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param get_next_event: function returning the next event in a stream 2910ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 292248108c1c925791d926105f42212b1033213a4dcGilad Arnold @return None if event complies, an error string otherwise. 2930ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2940ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 2950ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold base_timestamp = curr_timestamp = time.time() 2960ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold expired_timestamp = base_timestamp + timeout 2970ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold while curr_timestamp <= expired_timestamp: 2980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold new_event = get_next_event() 2990ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if new_event: 3000338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Event received after %s seconds', 3010338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold round(curr_timestamp - base_timestamp, 1)) 30216e76893c34739649a751f42b3881b57620d665cGilad Arnold results = [event.verify(new_event) for event in expected_events] 30316e76893c34739649a751f42b3881b57620d665cGilad Arnold return None if None in results else ' AND '.join(results) 3040ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3050ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # No new events, sleep for one second only (so we don't miss 3060ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # events at the end of the allotted timeout). 3070ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold time.sleep(1) 3080ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold curr_timestamp = time.time() 3090ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3100338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.error('Timeout expired') 311248108c1c925791d926105f42212b1033213a4dcGilad Arnold if on_timeout is None: 312248108c1c925791d926105f42212b1033213a4dcGilad Arnold return ('Waiting for event %s timed out after %d seconds' % 313fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo (' OR '.join(map(str, expected_events)), timeout)) 314248108c1c925791d926105f42212b1033213a4dcGilad Arnold return on_timeout 3150ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3160ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3170ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass UpdateEventLogVerifier(object): 3180ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies update event chains on a devserver update log.""" 31903901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold def __init__(self, event_log_url, url_request_timeout=None): 3200ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._event_log_url = event_log_url 32103901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold self._url_request_timeout = url_request_timeout 3220ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._event_log = [] 3230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._num_consumed_events = 0 3240ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3250ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 326fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo def verify_expected_events_chain(self, expected_event_chain): 327ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa """Verify a given event chain. 328ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa 329ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa @param expected_event_chain: instance of expected event chain. 330ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 331ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify the an 332ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa event. 333ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa """ 334ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa expected_event_chain.verify(self._get_next_log_event) 3350ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3360ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3370ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def _get_next_log_event(self): 3380ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Returns the next event in an event log. 3390ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3400ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold Uses the URL handed to it during initialization to obtain the host log 3410ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold from a devserver. If new events are encountered, the first of them is 3420ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold consumed and returned. 3430ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3440ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return The next new event in the host log, as reported by devserver; 34503901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold None if no such event was found or an error occurred. 3460ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3470ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 3480ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # (Re)read event log from devserver, if necessary. 3490ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if len(self._event_log) <= self._num_consumed_events: 35003901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold try: 35103901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold if self._url_request_timeout: 35203901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold conn = urllib2.urlopen(self._event_log_url, 35303901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold timeout=self._url_request_timeout) 35403901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold else: 35503901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold conn = urllib2.urlopen(self._event_log_url) 35603901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold except urllib2.URLError, e: 3570338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.warning('Failed to read event log url: %s', e) 35803901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold return None 359a0261611f9be78ee9d456fd50bea81e9eda07c17Gilad Arnold except socket.timeout, e: 360a0261611f9be78ee9d456fd50bea81e9eda07c17Gilad Arnold logging.warning('Timed out reading event log url: %s', e) 361a0261611f9be78ee9d456fd50bea81e9eda07c17Gilad Arnold return None 36203901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold 3630ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold event_log_resp = conn.read() 3640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold conn.close() 3650ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._event_log = json.loads(event_log_resp) 3660ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 36703901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold # Return next new event, if one is found. 3680ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if len(self._event_log) > self._num_consumed_events: 3697572b05fd3356b2ddf6866958e80c7885e44647bGilad Arnold new_event = { 3707572b05fd3356b2ddf6866958e80c7885e44647bGilad Arnold key: str(val) for key, val 3717572b05fd3356b2ddf6866958e80c7885e44647bGilad Arnold in self._event_log[self._num_consumed_events].iteritems() 3727572b05fd3356b2ddf6866958e80c7885e44647bGilad Arnold } 3730ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._num_consumed_events += 1 3740338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Consumed new event: %s', new_event) 3750ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return new_event 3760ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3770ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 378793344b359304c31d78197788b55cfbbe2636025Chris Sosaclass OmahaDevserverFailedToStart(error.TestError): 379793344b359304c31d78197788b55cfbbe2636025Chris Sosa """Raised when a omaha devserver fails to start.""" 380793344b359304c31d78197788b55cfbbe2636025Chris Sosa 381793344b359304c31d78197788b55cfbbe2636025Chris Sosa 3820ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass OmahaDevserver(object): 3830ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Spawns a test-private devserver instance.""" 384793344b359304c31d78197788b55cfbbe2636025Chris Sosa # How long to wait for a devserver to start. 38552c35724507ec105053d2af792fe161a627e05c1Alex Deymo _WAIT_FOR_DEVSERVER_STARTED_SECONDS = 30 386793344b359304c31d78197788b55cfbbe2636025Chris Sosa 387260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # How long to sleep (seconds) between checks to see if a devserver is up. 38803901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold _WAIT_SLEEP_INTERVAL = 1 3890ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3906f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # Max devserver execution time (seconds); used with timeout(1) to ensure we 3916f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # don't have defunct instances hogging the system. 3926f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold _DEVSERVER_TIMELIMIT_SECONDS = 12 * 60 * 60 393793344b359304c31d78197788b55cfbbe2636025Chris Sosa 394793344b359304c31d78197788b55cfbbe2636025Chris Sosa 395260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def __init__(self, omaha_host, devserver_dir, update_payload_staged_url): 3960ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Starts a private devserver instance, operating at Omaha capacity. 3970ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param omaha_host: host address where the devserver is spawned. 39903901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold @param devserver_dir: path to the devserver source directory 400ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param update_payload_staged_url: URL to provision for update requests. 4010ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 4020ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 403ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa if not update_payload_staged_url: 4040338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold raise error.TestError('Missing update payload url') 4050ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 4066c55bdb98e967675456a71a0971b81058536cac8Chris Sosa self._omaha_host = omaha_host 407260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid = 0 408260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_port = 0 # Determined later from devserver portfile. 4096c55bdb98e967675456a71a0971b81058536cac8Chris Sosa self._devserver_dir = devserver_dir 410ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._update_payload_staged_url = update_payload_staged_url 4116c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 4126c55bdb98e967675456a71a0971b81058536cac8Chris Sosa self._devserver_ssh = hosts.SSHHost(self._omaha_host, 4136c55bdb98e967675456a71a0971b81058536cac8Chris Sosa user=os.environ['USER']) 414260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 4153563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa # Temporary files for various devserver outputs. 4163563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_logfile = None 417238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo self._devserver_stdoutfile = None 4183563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_portfile = None 4193563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_pidfile = None 4203563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_static_dir = None 4213563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 4223563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 4233563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa def _cleanup_devserver_files(self): 4243563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa """Cleans up the temporary devserver files.""" 425238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo for filename in (self._devserver_logfile, self._devserver_stdoutfile, 426238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo self._devserver_portfile, self._devserver_pidfile): 427238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo if filename: 428238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo self._devserver_ssh.run('rm -f %s' % filename, 429238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo ignore_status=True) 4303563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 4313563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa if self._devserver_static_dir: 4323563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_ssh.run('rm -rf %s' % self._devserver_static_dir, 4333563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa ignore_status=True) 4343563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 435260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 4363563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa def _create_tempfile_on_devserver(self, label, dir=False): 4373563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa """Creates a temporary file/dir on the devserver and returns its path. 438260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 439260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @param label: Identifier for the file context (string, no whitespaces). 4403563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa @param dir: If True, create a directory instead of a file. 441260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 442260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @raises test.TestError: If we failed to invoke mktemp on the server. 443260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @raises OmahaDevserverFailedToStart: If tempfile creation failed. 444260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """ 445260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold remote_cmd = 'mktemp --tmpdir devserver-%s.XXXXXX' % label 4463563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa if dir: 4473563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa remote_cmd += ' --directory' 4483563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 449260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 450260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold result = self._devserver_ssh.run(remote_cmd, ignore_status=True) 451260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except error.AutoservRunError as e: 452260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._log_and_raise_remote_ssh_error(e) 453260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if result.exit_status != 0: 454260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold raise OmahaDevserverFailedToStart( 455260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'Could not create a temporary %s file on the devserver, ' 456a7412a90ffefac2b6314726b284af1b31d6bd797Alex Deymo 'error output: "%s"' % (label, result.stderr)) 457260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return result.stdout.strip() 458260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 459260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @staticmethod 460260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _log_and_raise_remote_ssh_error(e): 461260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Logs failure to ssh remote, then raises a TestError.""" 462260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.debug('Failed to ssh into the devserver: %s', e) 463260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.error('If you are running this locally it means you did not ' 464260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'configure ssh correctly.') 465260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold raise error.TestError('Failed to ssh into the devserver: %s' % e) 466260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 467260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 468260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _read_int_from_devserver_file(self, filename): 469260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Reads and returns an integer value from a file on the devserver.""" 470260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return int(self._get_devserver_file_content(filename).strip()) 4710ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 4726c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 473793344b359304c31d78197788b55cfbbe2636025Chris Sosa def _wait_for_devserver_to_start(self): 474793344b359304c31d78197788b55cfbbe2636025Chris Sosa """Waits until the devserver starts within the time limit. 475793344b359304c31d78197788b55cfbbe2636025Chris Sosa 476260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold Infers and sets the devserver PID and serving port. 477260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 478793344b359304c31d78197788b55cfbbe2636025Chris Sosa Raises: 479793344b359304c31d78197788b55cfbbe2636025Chris Sosa OmahaDevserverFailedToStart: If the time limit is reached and we 480793344b359304c31d78197788b55cfbbe2636025Chris Sosa cannot connect to the devserver. 481793344b359304c31d78197788b55cfbbe2636025Chris Sosa """ 482260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # Compute the overall timeout. 483260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold deadline = time.time() + self._WAIT_FOR_DEVSERVER_STARTED_SECONDS 484260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 485260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # First, wait for port file to be filled and determine the server port. 48694b9ad4983cc735e162a3549c1628d08241b0d57Gilad Arnold logging.warning('Waiting for devserver to start up.') 487260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold while time.time() < deadline: 488260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 489260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid = self._read_int_from_devserver_file( 490260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pidfile) 491260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_port = self._read_int_from_devserver_file( 492260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_portfile) 493260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.info('Devserver pid is %d, serving on port %d', 494260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid, self._devserver_port) 495260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold break 496260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except Exception: # Couldn't read file or corrupt content. 497260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold time.sleep(self._WAIT_SLEEP_INTERVAL) 498260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold else: 49952c35724507ec105053d2af792fe161a627e05c1Alex Deymo try: 50052c35724507ec105053d2af792fe161a627e05c1Alex Deymo self._devserver_ssh.run_output('uptime') 50152c35724507ec105053d2af792fe161a627e05c1Alex Deymo except error.AutoservRunError as e: 50252c35724507ec105053d2af792fe161a627e05c1Alex Deymo logging.debug('Failed to run uptime on the devserver: %s', e) 50394b9ad4983cc735e162a3549c1628d08241b0d57Gilad Arnold raise OmahaDevserverFailedToStart( 504260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'The test failed to find the pid/port of the omaha ' 50552c35724507ec105053d2af792fe161a627e05c1Alex Deymo 'devserver after %d seconds. Check the dumped devserver ' 50652c35724507ec105053d2af792fe161a627e05c1Alex Deymo 'logs and devserver load for more information.' % 50752c35724507ec105053d2af792fe161a627e05c1Alex Deymo self._WAIT_FOR_DEVSERVER_STARTED_SECONDS) 508260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 509260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # Check that the server is reponsding to network requests. 510260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.warning('Waiting for devserver to accept network requests.') 511260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold url = 'http://%s' % self.get_netloc() 512260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold while time.time() < deadline: 5139e2c98d8d0c61a816e736a387591950af9505504xixuan if dev_server.ImageServer.devserver_healthy(url, timeout_min=0.1): 514260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold break 515793344b359304c31d78197788b55cfbbe2636025Chris Sosa 516793344b359304c31d78197788b55cfbbe2636025Chris Sosa # TODO(milleral): Refactor once crbug.com/221626 is resolved. 517793344b359304c31d78197788b55cfbbe2636025Chris Sosa time.sleep(self._WAIT_SLEEP_INTERVAL) 518793344b359304c31d78197788b55cfbbe2636025Chris Sosa else: 519793344b359304c31d78197788b55cfbbe2636025Chris Sosa raise OmahaDevserverFailedToStart( 520793344b359304c31d78197788b55cfbbe2636025Chris Sosa 'The test failed to establish a connection to the omaha ' 521793344b359304c31d78197788b55cfbbe2636025Chris Sosa 'devserver it set up on port %d. Check the dumped ' 522260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'devserver logs for more information.' % 523260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_port) 524793344b359304c31d78197788b55cfbbe2636025Chris Sosa 525793344b359304c31d78197788b55cfbbe2636025Chris Sosa 5266c55bdb98e967675456a71a0971b81058536cac8Chris Sosa def start_devserver(self): 527793344b359304c31d78197788b55cfbbe2636025Chris Sosa """Starts the devserver and confirms it is up. 528793344b359304c31d78197788b55cfbbe2636025Chris Sosa 529793344b359304c31d78197788b55cfbbe2636025Chris Sosa Raises: 530260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold test.TestError: If we failed to spawn the remote devserver. 531793344b359304c31d78197788b55cfbbe2636025Chris Sosa OmahaDevserverFailedToStart: If the time limit is reached and we 532793344b359304c31d78197788b55cfbbe2636025Chris Sosa cannot connect to the devserver. 5336c55bdb98e967675456a71a0971b81058536cac8Chris Sosa """ 5342f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa update_payload_url_base, update_payload_path = self._split_url( 535ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._update_payload_staged_url) 5363563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 5373563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa # Allocate temporary files for various server outputs. 5383563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_logfile = self._create_tempfile_on_devserver('log') 539238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo self._devserver_stdoutfile = self._create_tempfile_on_devserver( 540238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo 'stdout') 5413563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_portfile = self._create_tempfile_on_devserver('port') 5423563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_pidfile = self._create_tempfile_on_devserver('pid') 5433563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_static_dir = self._create_tempfile_on_devserver( 5443563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 'static', dir=True) 5453563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 5466f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # Invoke the Omaha/devserver on the remote server. Will attempt to kill 5476f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # it with a SIGTERM after a predetermined timeout has elapsed, followed 5486f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # by SIGKILL if not dead within 30 seconds from the former signal. 5490ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold cmdlist = [ 5506f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold 'timeout', '-s', 'TERM', '-k', '30', 5516f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold str(self._DEVSERVER_TIMELIMIT_SECONDS), 5526c55bdb98e967675456a71a0971b81058536cac8Chris Sosa '%s/devserver.py' % self._devserver_dir, 5530ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--payload=%s' % update_payload_path, 554260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--port=0', 555260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--pidfile=%s' % self._devserver_pidfile, 556260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--portfile=%s' % self._devserver_portfile, 557260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--logfile=%s' % self._devserver_logfile, 5580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--remote_payload', 5590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--urlbase=%s' % update_payload_url_base, 5600ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--max_updates=1', 5610ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--host_log', 5623563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa '--static_dir=%s' % self._devserver_static_dir, 5631fd5e3042c6d8de3bdbb8cc169b5e0c5bd61af93Kevin Cernekee '--critical_update', 5640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold ] 565238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo remote_cmd = '( %s ) </dev/null >%s 2>&1 &' % ( 566238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo ' '.join(cmdlist), self._devserver_stdoutfile) 5676c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 568260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.info('Starting devserver with %r', remote_cmd) 569260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 570260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_ssh.run_output(remote_cmd) 571260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except error.AutoservRunError as e: 572260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._log_and_raise_remote_ssh_error(e) 5736c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 574260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 575260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._wait_for_devserver_to_start() 576260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except OmahaDevserverFailedToStart: 577260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._kill_remote_process() 578260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._dump_devserver_log() 579299e7788f7054dccab196dd7274f75ad41b66606Alex Deymo self._cleanup_devserver_files() 580260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold raise 58138ba6b79b19b5bdd9cfe71b26efd0c267768527aGilad Arnold 5826c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 583260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _kill_remote_process(self): 584260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Kills the devserver and verifies it's down; clears the remote pid.""" 585260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def devserver_down(): 586cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Ensure that the devserver process is down.""" 587260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return not self._remote_process_alive() 5886c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 589260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if devserver_down(): 5906c55bdb98e967675456a71a0971b81058536cac8Chris Sosa return 5916c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 592260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold for signal in 'SIGTERM', 'SIGKILL': 593260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold remote_cmd = 'kill -s %s %s' % (signal, self._devserver_pid) 594260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_ssh.run(remote_cmd) 595260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 596260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold client_utils.poll_for_condition( 597260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold devserver_down, sleep_interval=1, desc='devserver down') 598260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold break 599260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except client_utils.TimeoutError: 600260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.warning('Could not kill devserver with %s.', signal) 601260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold else: 602260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.warning('Failed to kill devserver, giving up.') 603260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 604260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid = None 6056c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 6066c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 607260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _remote_process_alive(self): 608260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Tests whether the remote devserver process is running.""" 609260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if not self._devserver_pid: 610260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return False 611260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold remote_cmd = 'test -e /proc/%s' % self._devserver_pid 612260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold result = self._devserver_ssh.run(remote_cmd, ignore_status=True) 613260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return result.exit_status == 0 6146c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 6156c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 6166c55bdb98e967675456a71a0971b81058536cac8Chris Sosa def get_netloc(self): 6176c55bdb98e967675456a71a0971b81058536cac8Chris Sosa """Returns the netloc (host:port) of the devserver.""" 618260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if not (self._devserver_pid and self._devserver_port): 6190338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold raise error.TestError('No running omaha/devserver') 6206c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 621260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return '%s:%s' % (self._omaha_host, self._devserver_port) 6220ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6236c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 6242f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa def get_update_url(self): 6252f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Returns the update_url you can use to update via this server.""" 6262f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa return urlparse.urlunsplit(('http', self.get_netloc(), '/update', 6272f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa '', '')) 6282f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 6292f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 630260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _get_devserver_file_content(self, filename): 631260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Returns the content of a file on the devserver.""" 6321391ae87d9941601dfc53377e2c187edcb0071dcGilad Arnold return self._devserver_ssh.run_output('cat %s' % filename, 6331391ae87d9941601dfc53377e2c187edcb0071dcGilad Arnold stdout_tee=None) 634260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 635260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 636260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _get_devserver_log(self): 637260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Obtain the devserver output.""" 638260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return self._get_devserver_file_content(self._devserver_logfile) 639260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 640260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 641238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo def _get_devserver_stdout(self): 642238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo """Obtain the devserver output in stdout and stderr.""" 643238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo return self._get_devserver_file_content(self._devserver_stdoutfile) 644238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo 645238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo 646260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _dump_devserver_log(self, logging_level=logging.ERROR): 6473563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa """Dump the devserver log to the autotest log. 64819426059c61c1b318b5d4bd04d70dacb63ec827dChris Sosa 64919426059c61c1b318b5d4bd04d70dacb63ec827dChris Sosa @param logging_level: logging level (from logging) to log the output. 65019426059c61c1b318b5d4bd04d70dacb63ec827dChris Sosa """ 6511391ae87d9941601dfc53377e2c187edcb0071dcGilad Arnold logging.log(logging_level, "Devserver stdout and stderr:\n" + 6521391ae87d9941601dfc53377e2c187edcb0071dcGilad Arnold snippet(self._get_devserver_stdout())) 6531391ae87d9941601dfc53377e2c187edcb0071dcGilad Arnold logging.log(logging_level, "Devserver log file:\n" + 6541391ae87d9941601dfc53377e2c187edcb0071dcGilad Arnold snippet(self._get_devserver_log())) 6550ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6560ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6570ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @staticmethod 6580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def _split_url(url): 6592f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Splits a URL into the URL base and path.""" 6600ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold split_url = urlparse.urlsplit(url) 6610ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold url_base = urlparse.urlunsplit( 6622f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa (split_url.scheme, split_url.netloc, '', '', '')) 6632f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa url_path = split_url.path 6642f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa return url_base, url_path.lstrip('/') 6650ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6660ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 667260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def stop_devserver(self): 668260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Kill remote process and wait for it to die, dump its output.""" 6696c55bdb98e967675456a71a0971b81058536cac8Chris Sosa if not self._devserver_pid: 670ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa logging.error('No running omaha/devserver.') 671ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa return 6726c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 6730338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Killing omaha/devserver') 674260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._kill_remote_process() 67519426059c61c1b318b5d4bd04d70dacb63ec827dChris Sosa logging.debug('Final devserver log before killing') 676260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._dump_devserver_log(logging.DEBUG) 6773563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._cleanup_devserver_files() 6780ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 6790ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 680f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnoldclass TestPlatform(object): 681f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """An interface and factory for platform-dependent functionality.""" 68215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 6832f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # Named tuple containing urls for staged urls needed for test. 6842f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # source_url: url to find the update payload for the source image. 6852f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # source_stateful_url: url to find the stateful payload for the source 6862f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # image. 6872f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # target_url: url to find the update payload for the target image. 6882f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # target_stateful_url: url to find the stateful payload for the target 6892f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # image. 690f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold StagedURLs = collections.namedtuple( 691f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 'StagedURLs', 6922f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa ['source_url', 'source_stateful_url', 'target_url', 6932f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 'target_stateful_url']) 6942f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 6950ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 696f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def __init__(self): 697f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold assert False, 'Cannot instantiate this interface' 698f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 699f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 700f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @staticmethod 701f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def create(host): 702f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Returns a TestPlatform implementation based on the host type. 703f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 704f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold *DO NOT* override this method. 705f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 706f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param host: a host object representing the DUT 707f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 708f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return A TestPlatform implementation. 709f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 710f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold os_type = host.get_os_type() 711585cbd6a5cc32db99c6745aa4333471b6b095b43Keith Haddow if os_type in ('cros', 'moblab'): 712f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return ChromiumOSTestPlatform(host) 713b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold if os_type == 'brillo': 714b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold return BrilloTestPlatform(host) 715f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 716f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise error.TestError('Unknown OS type reported by host: %s' % os_type) 717f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 7180ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 719f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def initialize(self, autotest_devserver, devserver_dir): 720f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Initialize the object. 7210ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 722f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param autotest_devserver: Instance of client.common_lib.dev_server to 723f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold use to reach the devserver instance for this 724f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold build. 725f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param devserver_dir: Path to devserver source tree. 7260ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 727f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 7280ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 7290ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 730f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def prep_artifacts(self, test_conf): 731f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Prepares update artifacts for the test. 73209706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 733f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold The test config must include 'source_payload_uri' and 734f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 'target_payload_uri'. In addition, it may include platform-specific 735f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold values as determined by the test control file. 73609706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 737f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param test_conf: Dictionary containing the test configuration. 73809706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 739f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return A tuple of staged URLs. 740f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 741f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @raise error.TestError on failure. 74209706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold """ 743f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 74409706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 74509706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 746f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def reboot_device(self): 747f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Reboots the device.""" 748f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 749f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 750f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 751f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def prep_device_for_update(self, source_release): 752f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Prepares the device for update. 753f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 7547ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold @param source_release: Source release version (string), or None. 755f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 756f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @raise error.TestError on failure. 757f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 758f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 759f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 760f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 761f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def get_active_slot(self): 762f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Returns the active boot slot of the device.""" 763f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 764f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 765f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 766f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def start_update_perf(self, bindir): 767f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Starts performance monitoring (if available). 768f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 769f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param bindir: Directory containing test binary files. 770f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 771f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 772f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 773f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 774f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def stop_update_perf(self): 775f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Stops performance monitoring and returns data (if available). 776f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 777f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return Dictionary containing performance attributes. 778f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 779f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 780f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 781f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 782f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def trigger_update(self, omaha_devserver): 783f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Kicks off an update. 784f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 785f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param omaha_devserver: OmahaDevserver instance. 786f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 787f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 788f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 789f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 790f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def finalize_update(self): 791f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Performs post-update procedures.""" 792f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 793f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 794f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 795f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def get_update_log(self, num_lines): 796f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Returns the update log. 797f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 798f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param num_lines: Number of log lines to return (tail), zero for all. 799f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 800f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return String containing the last |num_lines| from the update log. 801f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 802f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 803f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 804f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 805f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def check_device_after_update(self, target_release): 806f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Runs final sanity checks. 807f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 8087ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold @param target_release: Target release version (string), or None. 809f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 810f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @raise error.TestError on failure. 811f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 812f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 813f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 814f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 815f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnoldclass ChromiumOSTestPlatform(TestPlatform): 816f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """A TestPlatform implementation for Chromium OS.""" 817f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 818f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _STATEFUL_UPDATE_FILENAME = 'stateful.tgz' 819f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _LOGINABLE_MINIMUM_RELEASE = 5110 820f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 821f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def __init__(self, host): 822f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._host = host 823f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._autotest_devserver = None 824f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._devserver_dir = None 825f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._staged_urls = None 826f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._perf_mon_pid = None 827f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 828f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 829f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _stage_payload(self, devserver_label, filename, archive_url=None): 8302f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Stage the given payload onto the devserver. 8310ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8322f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa Works for either a stateful or full/delta test payload. Expects the 8332f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa gs_path or a combo of devserver_label + filename. 8340ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8352f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param devserver_label: The build name e.g. x86-mario-release/<version>. 8362f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa If set, assumes default gs archive bucket and 8372f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa requires filename to be specified. 8382f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param filename: In conjunction with devserver_label, if just specifying 8392f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa the devserver label name, this is which file are you 8402f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa downloading. 84115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @param archive_url: An optional GS archive location, if not using the 84215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold devserver's default. 843ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa 8440ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return URL of the staged payload on the server. 8450ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8460ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @raise error.TestError if there's a problem with staging. 8470ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8480ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 8492f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa try: 850f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._autotest_devserver.stage_artifacts( 85172f48be6c3f7e30edc6ff9a785f9c4cb53521af4Don Garrett image=devserver_label, files=[filename], 85272f48be6c3f7e30edc6ff9a785f9c4cb53521af4Don Garrett archive_url=archive_url) 853f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return self._autotest_devserver.get_staged_file_url(filename, 854f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver_label) 8552f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa except dev_server.DevServerException, e: 8560338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold raise error.TestError('Failed to stage payload: %s' % e) 8570ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 8580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 859f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _stage_payload_by_uri(self, payload_uri): 86015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """Stage a payload based on its GS URI. 86115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 86215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold This infers the build's label, filename and GS archive from the 86315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold provided GS URI. 86415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 86515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @param payload_uri: The full GS URI of the payload. 86615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 86715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @return URL of the staged payload on the server. 86815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 86915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @raise error.TestError if there's a problem with staging. 87015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 87115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """ 87215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold archive_url, _, filename = payload_uri.rpartition('/') 87315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold devserver_label = urlparse.urlsplit(archive_url).path.strip('/') 87494694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold return self._stage_payload(devserver_label, filename, 87594694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold archive_url=archive_url) 87615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 87715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 878cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @staticmethod 879cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold def _payload_to_update_url(payload_url): 8802f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Given a update or stateful payload url, returns the update url.""" 8817231260da421abdf5ceceff6ab60155936dca21fChris Sosa # We want to transform it to the correct omaha url which is 8827231260da421abdf5ceceff6ab60155936dca21fChris Sosa # <hostname>/update/...LABEL. 8832f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa base_url = payload_url.rpartition('/')[0] 8842f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa return base_url.replace('/static/', '/update/') 8852f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 8862f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 88715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold def _get_stateful_uri(self, build_uri): 88815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """Returns a complete GS URI of a stateful update given a build path.""" 88915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold return '/'.join([build_uri.rstrip('/'), self._STATEFUL_UPDATE_FILENAME]) 89015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 89115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 89215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold def _payload_to_stateful_uri(self, payload_uri): 89315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """Given a payload GS URI, returns the corresponding stateful URI.""" 89415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold build_uri = payload_uri.rpartition('/')[0] 895d8b9093f06cb882f7f46ca2f51d06630c9004f6dGwendal Grignou if build_uri.endswith('payloads'): 896d8b9093f06cb882f7f46ca2f51d06630c9004f6dGwendal Grignou build_uri = build_uri.rpartition('/')[0] 89715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold return self._get_stateful_uri(build_uri) 8982f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 8992f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 900f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _update_via_test_payloads(self, omaha_host, payload_url, stateful_url, 901f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold clobber): 902cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Given the following update and stateful urls, update the DUT. 903cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 904cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold Only updates the rootfs/stateful if the respective url is provided. 905cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 906cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param omaha_host: If updating rootfs, redirect updates through this 907cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold host. Should be None iff payload_url is None. 908cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param payload_url: If set, the specified url to find the update 909cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold payload. 910cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param stateful_url: If set, the specified url to find the stateful 911cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold payload. 912cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param clobber: If True, do a clean install of stateful. 913cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """ 914cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold def perform_update(url, is_stateful): 915cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Perform a rootfs/stateful update using given URL. 916cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 917cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param url: URL to update from. 918cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param is_stateful: Whether this is a stateful or rootfs update. 919cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """ 920cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if url: 921cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold updater = autoupdater.ChromiumOSUpdater(url, host=self._host) 922cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if is_stateful: 923cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold updater.update_stateful(clobber=clobber) 924cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold else: 9259e30d201214e586d185b497dea9a13a7e8d0495eGilad Arnold updater.update_image() 926cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 927cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold # We create a OmahaDevserver to redirect blah.bin to update/. This 928cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold # allows us to use any payload filename to serve an update. 929cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold temp_devserver = None 930cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold try: 9316273f5a63be4a2695b19cc76189607def69f5b27Gwendal Grignou if omaha_host: 932cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold temp_devserver = OmahaDevserver( 9336273f5a63be4a2695b19cc76189607def69f5b27Gwendal Grignou omaha_host, self._devserver_dir, 9346273f5a63be4a2695b19cc76189607def69f5b27Gwendal Grignou payload_url or stateful_url) 935cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold temp_devserver.start_devserver() 9366273f5a63be4a2695b19cc76189607def69f5b27Gwendal Grignou if payload_url: 937cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold payload_url = temp_devserver.get_update_url() 938cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 939cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold stateful_url = self._payload_to_update_url(stateful_url) 940cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 941cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold perform_update(payload_url, False) 942cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold perform_update(stateful_url, True) 943cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold finally: 944cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if temp_devserver: 945260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold temp_devserver.stop_devserver() 9462f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 9472f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 948f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _install_source_version(self, devserver_hostname, image_url, 949f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold stateful_url): 9502f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Prepare the specified host with the image given by the urls. 9512f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 952ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param devserver_hostname: If updating rootfs, redirect updates 953ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa through this host. Should be None iff 954ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa image_url is None. 9552f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param image_url: If set, the specified url to find the source image 9562f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa or full payload for the source image. 9572f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param stateful_url: If set, the specified url to find the stateful 9582f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa payload. 9592f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """ 96003286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou # Reboot to get us into a clean state. 96103286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou self._host.reboot() 9624cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold try: 9634cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # Since we are installing the source image of the test, clobber 9644cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # stateful. 965f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._update_via_test_payloads(devserver_hostname, image_url, 96694694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold stateful_url, True) 9671b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold except OmahaDevserverFailedToStart as e: 9681b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold logging.fatal('Failed to start private devserver for installing ' 9691b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'the source image (%s) on the DUT', image_url) 9701b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold raise error.TestError( 9711b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'Failed to start private devserver for installing the ' 9721b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'source image on the DUT: %s' % e) 9731b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold except error.AutoservRunError as e: 97403286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou logging.fatal('Error re-imaging the DUT with ' 97503286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou 'the source image from %s', image_url) 97603286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou raise error.TestError('Failed to install ' 97703286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou 'the source image DUT: %s' % e) 97803286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou self._host.reboot() 97903286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou 98003286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou # If powerwashed, need to reinstall stateful_url 98103286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou if not self._host.check_rsync(): 98203286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou logging.warn('Device has been powerwashed, need to reinstall ' 98303286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou 'stateful from %s', stateful_url) 98403286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou self._update_via_test_payloads(devserver_hostname, None, 98503286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou stateful_url, True) 98603286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou self._host.reboot() 987f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 988f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 989f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _stage_artifacts_onto_devserver(self, test_conf): 9902f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Stages artifacts that will be used by the test onto the devserver. 9912f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 9922f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param test_conf: a dictionary containing test configuration values 9932f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 994f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return a StagedURLs tuple containing the staged urls. 995f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa """ 9960338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Staging images onto autotest devserver (%s)', 997f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._autotest_devserver.url()) 998f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 99915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_source_url = None 100015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_source_stateful_url = None 10019cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold try: 10029cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold source_payload_uri = test_conf['source_payload_uri'] 10039cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold except KeyError: 10049cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold # TODO(garnold) Remove legacy key support once control files on all 10059cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold # release branches have caught up. 10069cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold source_payload_uri = test_conf['source_image_uri'] 10074cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold if source_payload_uri: 100894694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold staged_source_url = self._stage_payload_by_uri(source_payload_uri) 10094cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold 10104cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # In order to properly install the source image using a full 10114cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # payload we'll also need the stateful update that comes with it. 10124cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # In general, tests may have their source artifacts in a different 10134cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # location than their payloads. This is determined by whether or 10144cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # not the source_archive_uri attribute is set; if it isn't set, 10154cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # then we derive it from the dirname of the source payload. 10164cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_archive_uri = test_conf.get('source_archive_uri') 10174cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold if source_archive_uri: 10184cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_stateful_uri = self._get_stateful_uri(source_archive_uri) 10192f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa else: 10204cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_stateful_uri = self._payload_to_stateful_uri( 10214cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_payload_uri) 1022fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold 10234cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold staged_source_stateful_url = self._stage_payload_by_uri( 102494694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold source_stateful_uri) 102515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 10264cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # Log source image URLs. 10274cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold logging.info('Source full payload from %s staged at %s', 10284cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_payload_uri, staged_source_url) 10294cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold if staged_source_stateful_url: 10304cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold logging.info('Source stateful update from %s staged at %s', 10314cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_stateful_uri, staged_source_stateful_url) 103215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 103315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_payload_uri = test_conf['target_payload_uri'] 103494694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold staged_target_url = self._stage_payload_by_uri(target_payload_uri) 103515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri = None 10360e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold staged_target_stateful_url = None 103715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_archive_uri = test_conf.get('target_archive_uri') 10380e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold if target_archive_uri: 10390e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold target_stateful_uri = self._get_stateful_uri(target_archive_uri) 10402f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa else: 10410e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold # Attempt to get the job_repo_url to find the stateful payload for 10420e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold # the target image. 1043b9d7adf07aec05db6a3f1a8b74f45abd7a87c74aPrathmesh Prabhu job_repo_url = afe_utils.get_host_attribute( 1044b9d7adf07aec05db6a3f1a8b74f45abd7a87c74aPrathmesh Prabhu self._host, self._host.job_repo_url_attribute) 1045d8b9093f06cb882f7f46ca2f51d06630c9004f6dGwendal Grignou if not job_repo_url: 104615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri = self._payload_to_stateful_uri( 104715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_payload_uri) 10480e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold else: 10490e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold _, devserver_label = tools.get_devserver_build_from_package_url( 10500e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold job_repo_url) 10510e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold staged_target_stateful_url = self._stage_payload( 105294694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold devserver_label, self._STATEFUL_UPDATE_FILENAME) 1053f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 10540e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold if not staged_target_stateful_url and target_stateful_uri: 105515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_stateful_url = self._stage_payload_by_uri( 105694694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold target_stateful_uri) 10572f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 1058fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold # Log target payload URLs. 105915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold logging.info('%s test payload from %s staged at %s', 106015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold test_conf['update_type'], target_payload_uri, 106115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_url) 10620338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Target stateful update from %s staged at %s', 106315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri or 'standard location', 106415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_stateful_url) 106515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 1066f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return self.StagedURLs(staged_source_url, staged_source_stateful_url, 1067f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold staged_target_url, staged_target_stateful_url) 1068f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1069f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1070c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen def _run_login_test(self, release_string): 1071c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen """Runs login_LoginSuccess test if it is supported by the release.""" 1072c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # Only do login tests with recent builds, since they depend on 1073c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # some binary compatibility with the build itself. 1074c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # '5116.0.0' -> ('5116', '0', '0') -> 5116 10757ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold if not release_string: 10767ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold logging.info('No release provided, skipping login test.') 10777ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold elif int(release_string.split('.')[0]) > self._LOGINABLE_MINIMUM_RELEASE: 1078c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # Login, to prove we can before/after the update. 1079c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen logging.info('Attempting to login (release %s).', release_string) 1080c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1081c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen client_at = autotest.Autotest(self._host) 10820c88356d674fbc2545000483603ea3bdb9d13529David Haddock client_at.run_test('login_LoginSuccess', arc_mode='enabled') 1083c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen else: 1084c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen logging.info('Not attempting login test because %s is older than ' 1085c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen '%d.', release_string, self._LOGINABLE_MINIMUM_RELEASE) 1086c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1087c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1088f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _start_perf_mon(self, bindir): 108931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """Starts monitoring performance and resource usage on a DUT. 109031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 109131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen Call _stop_perf_mon() with the returned PID to stop monitoring 109231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen and collect the results. 109331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1094f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param bindir: Directoy containing monitoring script. 1095f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1096f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return The PID of the newly created DUT monitoring process. 109731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """ 109831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # We can't assume much about the source image so we copy the 109931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # performance monitoring script to the DUT directly. 1100f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold path = os.path.join(bindir, 'update_engine_performance_monitor.py') 110131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen self._host.send_file(path, '/tmp') 110231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen cmd = 'python /tmp/update_engine_performance_monitor.py --start-bg' 110331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen return int(self._host.run(cmd).stdout) 110431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 110531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 110631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen def _stop_perf_mon(self, perf_mon_pid): 110731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """Stops monitoring performance and resource usage on a DUT. 110831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 110931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen @param perf_mon_pid: the PID returned from _start_perf_mon(). 111031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1111f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return Dictionary containing performance attributes, or None if 1112f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold unavailable. 111331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """ 111431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Gracefully handle problems with performance monitoring by 111531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # just returning None. 111631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen try: 111731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen cmd = ('python /tmp/update_engine_performance_monitor.py ' 111831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen '--stop-bg=%d') % perf_mon_pid 111931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen perf_json_txt = self._host.run(cmd).stdout 112031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen return json.loads(perf_json_txt) 112131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen except Exception as e: 112231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen logging.warning('Failed to parse output from ' 112331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'update_engine_performance_monitor.py: %s', e) 112431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen return None 112531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 112631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1127f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Interface overrides. 1128f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # 1129f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def initialize(self, autotest_devserver, devserver_dir): 1130f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._autotest_devserver = autotest_devserver 1131f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._devserver_dir = devserver_dir 1132f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1133f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1134f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def reboot_device(self): 1135f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._host.reboot() 1136f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1137f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1138f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def prep_artifacts(self, test_conf): 1139f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._staged_urls = self._stage_artifacts_onto_devserver(test_conf) 1140f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return self._staged_urls 1141f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1142f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1143f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def prep_device_for_update(self, source_release): 1144f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Install the source version onto the DUT. 1145f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if self._staged_urls.source_url: 11469b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold logging.info('Installing a source image on the DUT') 1147f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver_hostname = urlparse.urlparse( 1148f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._autotest_devserver.url()).hostname 1149f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._install_source_version(devserver_hostname, 1150f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._staged_urls.source_url, 1151f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._staged_urls.source_stateful_url) 1152f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1153f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Make sure we can login before the update. 1154f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._run_login_test(source_release) 1155f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1156f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1157f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def get_active_slot(self): 1158f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return self._host.run('rootdev -s').stdout.strip() 1159f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1160f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1161f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def start_update_perf(self, bindir): 1162f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if self._perf_mon_pid is None: 1163f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._perf_mon_pid = self._start_perf_mon(bindir) 1164f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1165f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1166f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def stop_update_perf(self): 1167f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold perf_data = None 1168f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if self._perf_mon_pid is not None: 1169f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold perf_data = self._stop_perf_mon(self._perf_mon_pid) 1170f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._perf_mon_pid = None 1171f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1172f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return perf_data 1173f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1174f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1175f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def trigger_update(self, omaha_devserver): 1176f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold updater = autoupdater.ChromiumOSUpdater( 1177f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold omaha_devserver.get_update_url(), host=self._host) 1178f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold updater.trigger_update() 1179f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1180f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1181f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def finalize_update(self): 1182f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._update_via_test_payloads( 118394694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold None, None, self._staged_urls.target_stateful_url, False) 1184f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1185f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1186f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def get_update_log(self, num_lines): 1187f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return self._host.run_output( 1188fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 'tail -n %d /var/log/update_engine.log' % num_lines, 1189fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold stdout_tee=None) 1190f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1191f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1192f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def check_device_after_update(self, target_release): 1193f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Make sure we can login after update. 1194f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._run_login_test(target_release) 1195f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1196f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1197b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnoldclass BrilloTestPlatform(TestPlatform): 1198b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold """A TestPlatform implementation for Brillo.""" 1199b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1200b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold _URL_DEFAULT_PORT = 80 1201b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold _DUT_LOCALHOST = '127.0.0.1' 1202b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1203b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def __init__(self, host): 1204b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold self._host = host 12059b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._autotest_devserver = None 12069b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._devserver_dir = None 12079b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._staged_urls = None 1208b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold self._forwarding_ports = set() 1209b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1210b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1211b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold @classmethod 1212b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold def _get_host_port(cls, url): 1213b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold """Returns the host and port values from a given URL. 1214b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1215b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold @param url: The URL from which the values are extracted. 1216b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1217b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold @return A pair consisting of the host and port strings. 1218b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold """ 1219b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold host, _, port = urlparse.urlsplit(url).netloc.partition(':') 1220b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold return host, port or str(cls._URL_DEFAULT_PORT) 1221b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1222b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1223b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold def _install_rev_forwarding(self, port=None): 1224b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold """Installs reverse forwarding rules via ADB. 12259b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 1226b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold @param port: The TCP port we want forwarded; if None, installs all 1227b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold previously configured ports. 1228b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold """ 1229b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold ports = self._forwarding_ports if port is None else [port] 1230b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold for port in ports: 1231b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold port_spec = 'tcp:%s' % port 1232b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._host.add_forwarding(port_spec, port_spec, reverse=True) 1233b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1234b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1235b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold def _add_rev_forwarding(self, url): 1236b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold """Configures reverse port forwarding and adjusts the given URL. 1237b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1238b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold This extracts the port from the URL, adds it to the set of configured 1239b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold forwarding ports, installs it to the DUT, then returns the adjusted URL 1240b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold for use by the DUT. 1241b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1242b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold @param url: The URL for which we need to establish forwarding. 1243b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1244b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold @return: The adjusted URL for use on the DUT. 12459b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold """ 12469b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold if url: 1247b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold host, port = self._get_host_port(url) 1248b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold if port not in self._forwarding_ports: 1249b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._forwarding_ports.add(port) 1250b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._install_rev_forwarding(port=port) 1251b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold url = url.replace(host, self._DUT_LOCALHOST, 1) 1252b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold return url 12539b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 12549b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 1255b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold def _remove_rev_forwarding(self, url=None): 1256b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold """Removes a reverse port forwarding. 1257b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1258b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold @param url: The URL for which forwarding was established; if None, 1259b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold removes all previously configured ports. 1260b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold """ 1261b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold ports = set() 1262b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold if url is None: 1263b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold ports.update(self._forwarding_ports) 1264b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold else: 1265b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold _, port = self._get_host_port(url) 1266b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold if port in self._forwarding_ports: 1267b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold ports.add(port) 1268b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1269b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold # TODO(garnold) Enable once ADB port removal is fixed (b/24771474): 1270b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold # for port in ports: 1271b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold # self._host.remove_forwarding(src='tcp:%s' % port, reverse=True) 1272b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1273b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._forwarding_ports.difference_update(ports) 1274b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1275b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 12769b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold def _install_source_version(self, devserver_hostname, payload_url): 12779b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold """Installs a source version onto the test device. 12789b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 12799b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold @param devserver_hostname: Redirect updates through this host. 12809b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold @param payload_url: URL of staged payload for installing a source image. 12819b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold """ 12829b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold try: 12839b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold # Start a private Omaha server and update the DUT. 12849b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold temp_devserver = None 1285b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold url = None 12869b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold try: 12879b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold temp_devserver = OmahaDevserver( 12889b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold devserver_hostname, self._devserver_dir, payload_url) 12899b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold temp_devserver.start_devserver() 1290b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold url = self._add_rev_forwarding(temp_devserver.get_update_url()) 12919b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold updater = autoupdater.BrilloUpdater(url, host=self._host) 12929b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold updater.update_image() 12939b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold finally: 1294b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold if url: 1295b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._remove_rev_forwarding(url) 12969b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold if temp_devserver: 12979b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold temp_devserver.stop_devserver() 12989b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 12999b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold # Reboot the DUT. 13009b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self.reboot_device() 13019b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold except OmahaDevserverFailedToStart as e: 13029b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold logging.fatal('Failed to start private devserver for installing ' 13039b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 'the source payload (%s) on the DUT', payload_url) 13049b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold raise error.TestError( 13059b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 'Failed to start private devserver for installing the ' 13069b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 'source image on the DUT: %s' % e) 13079b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold except error.AutoservRunError as e: 13089b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold logging.fatal('Error re-imaging or rebooting the DUT with the ' 13099b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 'source image from %s', payload_url) 13109b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold raise error.TestError('Failed to install the source image or ' 13119b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 'reboot the DUT: %s' % e) 13129b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 13139b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 1314b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold # Interface overrides. 1315b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold # 1316b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def initialize(self, autotest_devserver, devserver_dir): 13179b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._autotest_devserver = autotest_devserver 13189b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._devserver_dir = devserver_dir 1319b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1320b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1321b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def reboot_device(self): 1322b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold self._host.reboot() 1323b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._install_rev_forwarding() 1324b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1325b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1326b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def prep_artifacts(self, test_conf): 1327b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold # TODO(garnold) Currently we don't stage anything and assume that the 1328b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold # provided URLs are of pre-staged payloads. We should implement staging 1329b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold # support once a release scheme for Brillo is finalized. 13309b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._staged_urls = self.StagedURLs( 1331b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._add_rev_forwarding(test_conf['source_payload_uri']), None, 1332b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._add_rev_forwarding(test_conf['target_payload_uri']), None) 13339b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold return self._staged_urls 1334b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1335b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1336b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def prep_device_for_update(self, source_release): 13379b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold # Install the source version onto the DUT. 13389b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold if self._staged_urls.source_url: 13399b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold logging.info('Installing a source image on the DUT') 13409b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold devserver_hostname = urlparse.urlparse( 13419b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._autotest_devserver.url()).hostname 13429b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._install_source_version(devserver_hostname, 13439b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._staged_urls.source_url) 1344b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1345b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1346b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def get_active_slot(self): 1347b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold return self._host.run('rootdev -s /system').stdout.strip() 1348b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1349b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1350b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def start_update_perf(self, bindir): 1351b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold pass 1352b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1353b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1354b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def stop_update_perf(self): 1355b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold pass 1356b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1357b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1358b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def trigger_update(self, omaha_devserver): 1359b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold url = self._add_rev_forwarding(omaha_devserver.get_update_url()) 1360b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold updater = autoupdater.BrilloUpdater(url, host=self._host) 1361b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold updater.trigger_update() 1362b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1363b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1364b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def finalize_update(self): 1365b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold pass 1366b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1367b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1368b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def get_update_log(self, num_lines): 1369b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold return self._host.run_output( 1370fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 'logcat -d -s update_engine | tail -n %d' % num_lines, 1371fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold stdout_tee=None) 1372b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1373b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1374b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def check_device_after_update(self, target_release): 1375b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._remove_rev_forwarding() 1376b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold # TODO(garnold) Port forwarding removal is broken in ADB (b/24771474). 1377b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold # Instead we reboot the device, which has the side-effect of flushing 1378b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold # all forwarding rules. Once fixed, the following should be removed. 137903322d32f30c95159e0651709a87132fa8b12bb4Gilad Arnold self.reboot_device() 1380b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1381b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1382f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnoldclass autoupdate_EndToEndTest(test.test): 1383f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Complete update test between two Chrome OS releases. 1384f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1385f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold Performs an end-to-end test of updating a ChromeOS device from one version 1386f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold to another. The test performs the following steps: 1387f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1388f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1. Stages the source (full) and target update payload on the central 1389f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver. 1390f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 2. Spawns a private Omaha-like devserver instance, configured to return 1391f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold the target (update) payload URL in response for an update check. 1392f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 3. Reboots the DUT. 1393f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 4. Installs a source image on the DUT (if provided) and reboots to it. 1394f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 5. Triggers an update check at the DUT. 1395f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 6. Watches as the DUT obtains an update and applies it. 1396f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 7. Reboots and repeats steps 5-6, ensuring that the next update check 1397f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold shows the new image version. 1398f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1399f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold Some notes on naming: 1400f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver: Refers to a machine running the Chrome OS Update Devserver. 1401f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold autotest_devserver: An autotest wrapper to interact with a devserver. 1402f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold Can be used to stage artifacts to a devserver. While 1403f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold this can also be used to update a machine, we do not 1404f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold use it for that purpose in this test as we manage 1405f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold updates with out own devserver instances (see below). 1406f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold omaha_devserver: This test's wrapper of a devserver running for the 1407f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold purposes of emulating omaha. This test controls the 1408f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold lifetime of this devserver instance and is separate 1409f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold from the autotest lab's devserver's instances which are 1410f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold only used for staging and hosting artifacts (because they 1411f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold scale). These are run on the same machines as the actual 1412f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold autotest devservers which are used for staging but on 1413f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold different ports. 1414f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold *staged_url's: In this case staged refers to the fact that these items 1415f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold are available to be downloaded statically from these urls 1416f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold e.g. 'localhost:8080/static/my_file.gz'. These are usually 1417f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold given after staging an artifact using a autotest_devserver 1418f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold though they can be re-created given enough assumptions. 1419f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold *update_url's: Urls refering to the update RPC on a given omaha devserver. 1420f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold Since we always use an instantiated omaha devserver to run 1421f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold updates, these will always reference an existing instance 1422f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold of an omaha devserver that we just created for the purposes 1423f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold of updating. 1424f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver_hostname: At the start of each test, we choose a devserver 1425f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold machine in the lab for the test. We use the devserver 1426f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold instance there (access by autotest_devserver) to stage 1427f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold artifacts. However, we also use the same host to start 1428f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold omaha devserver instances for updating machines with 1429f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold (that reference the staged paylaods on the autotest 1430f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver instance). This hostname refers to that 1431f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold machine we are using (since it's always the same for 1432f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold both staging/omaha'ing). 1433f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1434f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 1435f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold version = 1 1436f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1437f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Timeout periods, given in seconds. 1438f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_AFTER_SHUTDOWN_SECONDS = 10 1439f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_AFTER_UPDATE_SECONDS = 20 1440f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_USB_INSTALL_SECONDS = 4 * 60 1441f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_MP_RECOVERY_SECONDS = 8 * 60 1442f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_INITIAL_UPDATE_CHECK_SECONDS = 12 * 60 1443f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # TODO(sosa): Investigate why this needs to be so long (this used to be 1444f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # 120 and regressed). 1445f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_DOWNLOAD_STARTED_SECONDS = 4 * 60 1446f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_DOWNLOAD_COMPLETED_SECONDS = 10 * 60 1447f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_UPDATE_COMPLETED_SECONDS = 4 * 60 1448f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_UPDATE_CHECK_AFTER_REBOOT_SECONDS = 15 * 60 1449f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _DEVSERVER_HOSTLOG_REQUEST_TIMEOUT_SECONDS = 30 1450f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1451a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold # Logs and their whereabouts. 1452a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold _WHERE_UPDATE_LOG = ('update_engine log (in sysinfo or on the DUT, also ' 1453a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'included in the test log)') 1454a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold _WHERE_OMAHA_LOG = 'Omaha-devserver log (included in the test log)' 1455a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1456f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1457f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def initialize(self): 1458f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Sets up variables that will be used by test.""" 1459f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._host = None 1460f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._omaha_devserver = None 1461a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._source_image_installed = False 1462f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1463f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._devserver_dir = global_config.global_config.get_config_value( 1464f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 'CROS', 'devserver_dir', default=None) 1465f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if self._devserver_dir is None: 1466f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise error.TestError( 1467f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 'Path to devserver source tree not provided; please define ' 1468f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 'devserver_dir under [CROS] in your shadow_config.ini') 1469f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1470f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1471f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def cleanup(self): 1472f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Kill the omaha devserver if it's still around.""" 1473f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if self._omaha_devserver: 1474f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._omaha_devserver.stop_devserver() 1475f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1476f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._omaha_devserver = None 1477f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1478f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1479f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _dump_update_engine_log(self, test_platform): 1480f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Dumps relevant AU error log.""" 1481f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold try: 1482fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold error_log = test_platform.get_update_log(80) 1483fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold logging.error('Dumping snippet of update_engine log:\n%s', 1484fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold snippet(error_log)) 1485f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold except Exception: 1486f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Mute any exceptions we get printing debug logs. 1487f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold pass 1488f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1489f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 149031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen def _report_perf_data(self, perf_data): 149131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """Reports performance and resource data. 149231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1493f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold Currently, performance attributes are expected to include 'rss_peak' 1494f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold (peak memory usage in bytes). 1495f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1496f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param perf_data: A dictionary containing performance attributes. 149731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """ 149831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen rss_peak = perf_data.get('rss_peak') 149931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen if rss_peak: 150031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen rss_peak_kib = rss_peak / 1024 150131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen logging.info('Peak memory (RSS) usage on DUT: %d KiB', rss_peak_kib) 150231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen self.output_perf_value(description='mem_usage_peak', 150331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen value=int(rss_peak_kib), 150431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen units='KiB', 150531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen higher_is_better=False) 150631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen else: 150731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen logging.warning('No rss_peak key in JSON returned by ' 150831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'update_engine_performance_monitor.py') 150931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 151031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1511a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_initial_check(self, expected, actual, mismatched_attrs): 1512a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'version' in mismatched_attrs: 1513a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold err_msg = ('Initial update check was received but the reported ' 1514a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'version is different from what was expected.') 1515a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if self._source_image_installed: 1516a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold err_msg += (' The source payload we installed was probably ' 1517a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'incorrect or corrupt.') 1518a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold else: 1519a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold err_msg += (' The DUT is probably not running the correct ' 1520a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'source image.') 1521a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return err_msg 1522a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1523a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return 'A test bug occurred; inspect the test log.' 1524a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1525a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1526a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_intermediate(self, expected, actual, mismatched_attrs, action, 1527a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold problem): 1528a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'event_result' in mismatched_attrs: 15290ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold event_result = actual.get('event_result') 15300ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold reported = (('different than expected (%s)' % 15310ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold EVENT_RESULT_DICT[event_result]) 15320ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold if event_result else 'missing') 15330ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold return ('The updater reported result code is %s. This could be an ' 15340ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'updater bug or a connectivity problem; check the %s. For ' 15350ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'a detailed log of update events, check the %s.' % 15360ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold (reported, self._WHERE_UPDATE_LOG, self._WHERE_OMAHA_LOG)) 1537a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'event_type' in mismatched_attrs: 15380ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold event_type = actual.get('event_type') 15390ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold reported = ('different (%s)' % EVENT_TYPE_DICT[event_type] 15400ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold if event_type else 'missing') 15410ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold return ('Expected the updater to %s (%s) but received event type ' 15420ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'is %s. This could be an updater %s; check the ' 1543a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold '%s. For a detailed log of update events, check the %s.' % 15440ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold (action, EVENT_TYPE_DICT[expected['event_type']], reported, 15450ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold problem, self._WHERE_UPDATE_LOG, self._WHERE_OMAHA_LOG)) 1546a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'version' in mismatched_attrs: 1547a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('The updater reported an unexpected version despite ' 1548a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'previously reporting the correct one. This is most likely ' 1549a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'a bug in update engine; check the %s.' % 1550a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WHERE_UPDATE_LOG) 1551a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1552a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return 'A test bug occurred; inspect the test log.' 1553a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1554a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1555a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_download_started(self, expected, actual, mismatched_attrs): 1556a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return self._error_intermediate(expected, actual, mismatched_attrs, 1557a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'begin downloading', 1558a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'bug, crash or provisioning error') 1559a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1560a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1561a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_download_finished(self, expected, actual, mismatched_attrs): 1562a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return self._error_intermediate(expected, actual, mismatched_attrs, 1563a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'finish downloading', 'bug or crash') 1564a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1565a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1566a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_update_complete(self, expected, actual, mismatched_attrs): 1567a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return self._error_intermediate(expected, actual, mismatched_attrs, 1568a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'complete the update', 'bug or crash') 1569a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1570a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 157116e76893c34739649a751f42b3881b57620d665cGilad Arnold def _error_reboot_after_update(self, expected, actual, mismatched_attrs): 1572a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'event_result' in mismatched_attrs: 15730ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold event_result = actual.get('event_result') 15740ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold reported = ('different (%s)' % EVENT_RESULT_DICT[event_result] 15750ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold if event_result else 'missing') 1576a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('The updater was expected to reboot (%s) but reported ' 15770ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'result code is %s. This could be a failure to reboot, an ' 15780ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'updater bug or a connectivity problem; check the %s and ' 15790ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'the system log. For a detailed log of update events, ' 15800ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'check the %s.' % 15810ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold (EVENT_RESULT_DICT[expected['event_result']], reported, 1582a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WHERE_UPDATE_LOG, self._WHERE_OMAHA_LOG)) 1583a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'event_type' in mismatched_attrs: 15840ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold event_type = actual.get('event_type') 15850ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold reported = ('different (%s)' % EVENT_TYPE_DICT[event_type] 15860ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold if event_type else 'missing') 1587a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('Expected to successfully reboot into the new image (%s) ' 15880ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'but received event type is %s. This probably means that ' 15890ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'the new image failed to verify after reboot, possibly ' 15900ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'because the payload is corrupt. This might also be an ' 15910ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'updater bug or crash; check the %s. For a detailed log of ' 15920ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'update events, check the %s.' % 15930ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold (EVENT_TYPE_DICT[expected['event_type']], reported, 1594a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WHERE_UPDATE_LOG, self._WHERE_OMAHA_LOG)) 1595a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'version' in mismatched_attrs: 1596a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('The DUT rebooted after the update but reports a different ' 1597a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'image version than the one expected. This probably means ' 1598a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'that the payload we applied was incorrect or corrupt.') 1599a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'previous_version' in mismatched_attrs: 1600a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('The DUT rebooted after the update and reports the ' 1601a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'expected version. However, it reports a previous version ' 1602a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'that is different from the one previously reported. This ' 1603a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'is most likely a bug in update engine; check the %s.' % 1604a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WHERE_UPDATE_LOG) 1605a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1606a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return 'A test bug occurred; inspect the test log.' 1607a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1608a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1609a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _timeout_err(self, desc, timeout, event_type=None): 1610a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if event_type is not None: 1611a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold desc += ' (%s)' % EVENT_TYPE_DICT[event_type] 1612a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('Failed to receive %s within %d seconds. This could be a ' 1613a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'problem with the updater or a connectivity issue. For more ' 1614a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'details, check the %s.' % 1615a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold (desc, timeout, self._WHERE_UPDATE_LOG)) 1616a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1617a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1618f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def run_update_test(self, test_platform, test_conf): 1619ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Runs the actual update test once preconditions are met. 16200ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1621f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param test_platform: TestPlatform implementation. 1622ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param test_conf: A dictionary containing test configuration values 16230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1624ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify an update 1625ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa event. 16260ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 1627c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1628f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Record the active root partition. 1629f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold source_active_slot = test_platform.get_active_slot() 1630f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold logging.info('Source active slot: %s', source_active_slot) 16310ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 16327ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold source_release = test_conf['source_release'] 16337ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold target_release = test_conf['target_release'] 16347ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold 163531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Start the performance monitoring process on the DUT. 1636f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform.start_update_perf(self.bindir) 163731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen try: 163831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Trigger an update. 1639f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform.trigger_update(self._omaha_devserver) 16400ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 164131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Track update progress. 164231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen omaha_netloc = self._omaha_devserver.get_netloc() 164331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen omaha_hostlog_url = urlparse.urlunsplit( 164431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen ['http', omaha_netloc, '/api/hostlog', 164531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'ip=' + self._host.ip, '']) 164631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen logging.info('Polling update progress from omaha/devserver: %s', 164731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen omaha_hostlog_url) 164831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen log_verifier = UpdateEventLogVerifier( 164931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen omaha_hostlog_url, 165031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen self._DEVSERVER_HOSTLOG_REQUEST_TIMEOUT_SECONDS) 165131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 165231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Verify chain of events in a successful update process. 1653248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain = ExpectedUpdateEventChain() 1654248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain.add_event( 1655248108c1c925791d926105f42212b1033213a4dcGilad Arnold ExpectedUpdateEvent( 16567ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold version=source_release, 1657a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_error=self._error_initial_check), 1658a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_INITIAL_UPDATE_CHECK_SECONDS, 1659a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_timeout=self._timeout_err( 1660a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'an initial update check', 1661a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_INITIAL_UPDATE_CHECK_SECONDS)) 1662248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain.add_event( 1663248108c1c925791d926105f42212b1033213a4dcGilad Arnold ExpectedUpdateEvent( 1664248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_type=EVENT_TYPE_DOWNLOAD_STARTED, 1665248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_result=EVENT_RESULT_SUCCESS, 16667ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold version=source_release, 1667a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_error=self._error_download_started), 1668a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_DOWNLOAD_STARTED_SECONDS, 1669a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_timeout=self._timeout_err( 1670a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'a download started notification', 1671a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_DOWNLOAD_STARTED_SECONDS, 1672a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold event_type=EVENT_TYPE_DOWNLOAD_STARTED)) 1673248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain.add_event( 1674248108c1c925791d926105f42212b1033213a4dcGilad Arnold ExpectedUpdateEvent( 1675248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_type=EVENT_TYPE_DOWNLOAD_FINISHED, 1676248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_result=EVENT_RESULT_SUCCESS, 16777ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold version=source_release, 1678a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_error=self._error_download_finished), 1679a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_DOWNLOAD_COMPLETED_SECONDS, 1680a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_timeout=self._timeout_err( 1681a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'a download finished notification', 1682a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_DOWNLOAD_COMPLETED_SECONDS, 1683a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold event_type=EVENT_TYPE_DOWNLOAD_FINISHED)) 1684248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain.add_event( 1685248108c1c925791d926105f42212b1033213a4dcGilad Arnold ExpectedUpdateEvent( 1686248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_type=EVENT_TYPE_UPDATE_COMPLETE, 1687248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_result=EVENT_RESULT_SUCCESS, 16887ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold version=source_release, 1689a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_error=self._error_update_complete), 1690a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_UPDATE_COMPLETED_SECONDS, 1691a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_timeout=self._timeout_err( 1692a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'an update complete notification', 1693a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_UPDATE_COMPLETED_SECONDS, 1694a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold event_type=EVENT_TYPE_UPDATE_COMPLETE)) 169531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1696fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo log_verifier.verify_expected_events_chain(chain) 169731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 169831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Wait after an update completion (safety margin). 169931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen _wait(self._WAIT_AFTER_UPDATE_SECONDS, 'after update completion') 170031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen finally: 170131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Terminate perf monitoring process and collect its output. 1702f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold perf_data = test_platform.stop_update_perf() 170331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen if perf_data: 170431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen self._report_perf_data(perf_data) 1705f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 17064cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # Only update the stateful partition (the test updated the rootfs). 1707f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform.finalize_update() 17084cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold 1709f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # Reboot the DUT after the update. 1710bacc35bdb2fb44b0a760c05d364854cd92fb3f98Gilad Arnold test_platform.reboot_device() 17110ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1712f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # Trigger a second update check (again, test vs MP). 1713f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform.trigger_update(self._omaha_devserver) 17140ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1715f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # Observe post-reboot update check, which should indicate that the 1716f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # image version has been updated. 1717248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain = ExpectedUpdateEventChain() 1718fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo expected_events = [ 1719fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo ExpectedUpdateEvent( 1720fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo event_type=EVENT_TYPE_UPDATE_COMPLETE, 1721fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo event_result=EVENT_RESULT_SUCCESS_REBOOT, 1722fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo version=target_release, 1723fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo previous_version=source_release, 1724fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo on_error=self._error_reboot_after_update), 1725fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo # Newer versions send a "rebooted_after_update" message after reboot 1726fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo # with the previous version instead of another "update_complete". 1727fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo ExpectedUpdateEvent( 1728fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo event_type=EVENT_TYPE_REBOOTED_AFTER_UPDATE, 1729fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo event_result=EVENT_RESULT_SUCCESS, 1730fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo version=target_release, 1731fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo previous_version=source_release, 1732fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo on_error=self._error_reboot_after_update), 1733fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo ] 1734248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain.add_event( 1735fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo expected_events, 1736a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_UPDATE_CHECK_AFTER_REBOOT_SECONDS, 1737a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_timeout=self._timeout_err( 1738a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'a successful reboot notification', 1739a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_UPDATE_CHECK_AFTER_REBOOT_SECONDS, 1740a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold event_type=EVENT_TYPE_UPDATE_COMPLETE)) 1741ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1742fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo log_verifier.verify_expected_events_chain(chain) 1743f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1744f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Make sure we're using a different slot after the update. 1745f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold target_active_slot = test_platform.get_active_slot() 1746f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if target_active_slot == source_active_slot: 17471b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold err_msg = 'The active image slot did not change after the update.' 17487ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold if None in (source_release, target_release): 17497ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold err_msg += (' The DUT likely rebooted into the old image, which ' 17507ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold 'probably means that the payload we applied was ' 17517ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold 'corrupt. But since we did not check the source ' 17527ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold 'and/or target version we cannot say for sure.') 17537ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold elif source_release == target_release: 17541b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold err_msg += (' Given that the source and target versions are ' 17551b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'identical, the DUT likely rebooted into the old ' 17561b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'image. This probably means that the payload we ' 17571b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'applied was corrupt.') 17581b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold else: 17591b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold err_msg += (' This is strange since the DUT reported the ' 17601b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'correct target version. This is probably a system ' 17611b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'bug; check the DUT system log.') 17621b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold raise error.TestFail(err_msg) 17630338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1764f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold logging.info('Target active slot changed as expected: %s', 1765f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold target_active_slot) 1766eb300ac8af429e51f751b95ce375636fbb649e37Gilad Arnold 17670338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Update successful, test completed') 17680ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1769ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 17709cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold # TODO(garnold) Remove the use_servo argument once control files on all 17719cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold # release branches have caught up. 17724cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold def run_once(self, host, test_conf, use_servo=False): 1773ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Performs a complete auto update test. 1774ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1775ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param host: a host object representing the DUT 1776ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param test_conf: a dictionary containing test configuration values 17774cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold @param use_servo: DEPRECATED 1778ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1779ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raise error.TestError if anything went wrong with setting up the test; 1780ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa error.TestFail if any part of the test has failed. 1781ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1782ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """ 1783f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 1784ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._host = host 1785ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1786009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # Find a devserver to use. We first try to pick a devserver with the 1787009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # least load. In case all devservers' load are higher than threshold, 1788009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # fall back to the old behavior by picking a devserver based on the 1789009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # payload URI, with which ImageServer.resolve will return a random 1790009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # devserver based on the hash of the URI. 179101b28a630230336c3277dd7b9d375ee012931b77Dan Shi # The picked devserver needs to respect the location of the host if 179201b28a630230336c3277dd7b9d375ee012931b77Dan Shi # `prefer_local_devserver` is set to True or `restricted_subnets` is 179301b28a630230336c3277dd7b9d375ee012931b77Dan Shi # set. 179401b28a630230336c3277dd7b9d375ee012931b77Dan Shi hostname = self._host.hostname if self._host else None 179501b28a630230336c3277dd7b9d375ee012931b77Dan Shi least_loaded_devserver = dev_server.get_least_loaded_devserver( 179601b28a630230336c3277dd7b9d375ee012931b77Dan Shi hostname=hostname) 17974e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi if least_loaded_devserver: 17984e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi logging.debug('Choose the least loaded devserver: %s', 17994e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi least_loaded_devserver) 18004e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi autotest_devserver = dev_server.ImageServer(least_loaded_devserver) 18014e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi else: 1802009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi logging.warning('No devserver meets the maximum load requirement. ' 1803009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi 'Pick a random devserver to use.') 1804009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi autotest_devserver = dev_server.ImageServer.resolve( 180569b9b975fccab1ede1e8849ed17e7e655a9d6b48Dan Shi test_conf['target_payload_uri'], host.hostname) 1806ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa devserver_hostname = urlparse.urlparse( 1807ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver.url()).hostname 1808ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1809f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Obtain a test platform implementation. 1810f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform = TestPlatform.create(host) 1811f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform.initialize(autotest_devserver, self._devserver_dir) 1812f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1813ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # Stage source images and update payloads onto a devserver. 1814f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold staged_urls = test_platform.prep_artifacts(test_conf) 1815a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._source_image_installed = bool(staged_urls.source_url) 1816ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1817f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Prepare the DUT (install source version etc). 1818f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform.prep_device_for_update(test_conf['source_release']) 1819ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1820ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._omaha_devserver = OmahaDevserver( 1821f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver_hostname, self._devserver_dir, 1822f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold staged_urls.target_url) 1823ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._omaha_devserver.start_devserver() 1824c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1825ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa try: 1826f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self.run_update_test(test_platform, test_conf) 1827ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa except ExpectedUpdateEventChainFailed: 1828f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._dump_update_engine_log(test_platform) 1829ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa raise 1830f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 1831f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform.check_device_after_update(test_conf['target_release']) 1832