autoupdate_EndToEndTest.py revision 0ba4fcd882643427524c35522bf77959b57c6f48
10ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 20ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold# Use of this source code is governed by a BSD-style license that can be 30ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold# found in the LICENSE file. 40ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 52f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosaimport collections 60ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldimport json 70ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldimport logging 86c55bdb98e967675456a71a0971b81058536cac8Chris Sosaimport os 9a0261611f9be78ee9d456fd50bea81e9eda07c17Gilad Arnoldimport socket 1015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnoldimport time 110ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldimport urllib2 120ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldimport urlparse 1303901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold 146c55bdb98e967675456a71a0971b81058536cac8Chris Sosafrom autotest_lib.client.bin import utils as client_utils 156c55bdb98e967675456a71a0971b81058536cac8Chris Sosafrom autotest_lib.client.common_lib import error, global_config 160ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldfrom autotest_lib.client.common_lib.cros import autoupdater, dev_server 17d874a4d63dacfb6e8a74466eab5160e940aaa690Dan Shifrom autotest_lib.client.common_lib.cros.graphite import autotest_stats 188ddeb9c8d6df7eb2e033651e39f434ebdf8af3ccSimran Basifrom autotest_lib.server import autotest, hosts, test 192f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosafrom autotest_lib.server.cros.dynamic_suite import tools 200ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 210ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 220ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnolddef _wait(secs, desc=None): 230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Emits a log message and sleeps for a given number of seconds.""" 240338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold msg = 'Waiting %s seconds' % secs 250ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if desc: 260ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold msg += ' (%s)' % desc 270ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold logging.info(msg) 280ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold time.sleep(secs) 290ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 300ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 31ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosaclass ExpectedUpdateEventChainFailed(error.TestFail): 32ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Raised if we fail to receive an expected event in a chain.""" 33ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 340f27cafd72cd7c6aee752d0ec90de1b58e3b97ddGilad Arnoldclass RequiredArgumentMissing(error.TestError): 350f27cafd72cd7c6aee752d0ec90de1b58e3b97ddGilad Arnold """Raised if the test is missing a required argument.""" 36f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 37ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 380338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold# Update event types. 390338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_DOWNLOAD_COMPLETE = '1' 400338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_INSTALL_COMPLETE = '2' 410338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_UPDATE_COMPLETE = '3' 420338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_DOWNLOAD_STARTED = '13' 430338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_DOWNLOAD_FINISHED = '14' 44fac9a5d238337da91939328386c2fa4fdfb6d957Alex DeymoEVENT_TYPE_REBOOTED_AFTER_UPDATE = '54' 450338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 460338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold# Update event results. 470338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_ERROR = '0' 480338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_SUCCESS = '1' 490338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_SUCCESS_REBOOT = '2' 500338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_UPDATE_DEFERRED = '9' 510338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 52a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold# Omaha event types/results, from update_engine/omaha_request_action.h 53a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold# These are stored in dict form in order to easily print out the keys. 54a0ca5707ed10a6575ed290f341294331455f7769Gilad ArnoldEVENT_TYPE_DICT = { 55a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_TYPE_DOWNLOAD_COMPLETE: 'download_complete', 56a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_TYPE_INSTALL_COMPLETE: 'install_complete', 57a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_TYPE_UPDATE_COMPLETE: 'update_complete', 58a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_TYPE_DOWNLOAD_STARTED: 'download_started', 59fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo EVENT_TYPE_DOWNLOAD_FINISHED: 'download_finished', 60fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo EVENT_TYPE_REBOOTED_AFTER_UPDATE: 'rebooted_after_update' 61a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold} 62a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 63a0ca5707ed10a6575ed290f341294331455f7769Gilad ArnoldEVENT_RESULT_DICT = { 64a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_RESULT_ERROR: 'error', 65a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_RESULT_SUCCESS: 'success', 66a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_RESULT_SUCCESS_REBOOT: 'success_reboot', 67a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_RESULT_UPDATE_DEFERRED: 'update_deferred' 68a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold} 69a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 700338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 71fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnolddef snippet(text): 72fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold """Returns the text with start/end snip markers around it. 73fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 74fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold @param text: The snippet text. 75fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 76fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold @return The text with start/end snip markers around it. 77fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold """ 78fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold snip = '---8<---' * 10 79fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold start = '-- START -' 80fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold end = '-- END -' 81fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold return ('%s%s\n%s\n%s%s' % 82fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold (start, snip[len(start):], text, end, snip[len(end):])) 83fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 84fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 850ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass ExpectedUpdateEvent(object): 86248108c1c925791d926105f42212b1033213a4dcGilad Arnold """Defines an expected event in an update process.""" 8745f02ae47134953169805d281992c9edf0019250Chris Sosa 880338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold _ATTR_NAME_DICT_MAP = { 89a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'event_type': EVENT_TYPE_DICT, 90a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'event_result': EVENT_RESULT_DICT, 910338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold } 920338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 93a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold _VALID_TYPES = set(EVENT_TYPE_DICT.keys()) 94a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold _VALID_RESULTS = set(EVENT_RESULT_DICT.keys()) 9545f02ae47134953169805d281992c9edf0019250Chris Sosa 960ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __init__(self, event_type=None, event_result=None, version=None, 97248108c1c925791d926105f42212b1033213a4dcGilad Arnold previous_version=None, on_error=None): 98248108c1c925791d926105f42212b1033213a4dcGilad Arnold """Initializes an event expectation. 99248108c1c925791d926105f42212b1033213a4dcGilad Arnold 100248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param event_type: Expected event type. 101248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param event_result: Expected event result code. 102248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param version: Expected reported image version. 103248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param previous_version: Expected reported previous image version. 104248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param on_error: This is either an object to be returned when a received 105248108c1c925791d926105f42212b1033213a4dcGilad Arnold event mismatches the expectation, or a callable used 106248108c1c925791d926105f42212b1033213a4dcGilad Arnold for generating one. In the latter case, takes as 107248108c1c925791d926105f42212b1033213a4dcGilad Arnold input two attribute dictionaries (expected and actual) 108248108c1c925791d926105f42212b1033213a4dcGilad Arnold and an iterable of mismatched keys. If None, a generic 109248108c1c925791d926105f42212b1033213a4dcGilad Arnold message is returned. 110248108c1c925791d926105f42212b1033213a4dcGilad Arnold """ 1110338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if event_type and event_type not in self._VALID_TYPES: 11245f02ae47134953169805d281992c9edf0019250Chris Sosa raise ValueError('event_type %s is not valid.' % event_type) 11345f02ae47134953169805d281992c9edf0019250Chris Sosa 1140338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if event_result and event_result not in self._VALID_RESULTS: 11545f02ae47134953169805d281992c9edf0019250Chris Sosa raise ValueError('event_result %s is not valid.' % event_result) 11645f02ae47134953169805d281992c9edf0019250Chris Sosa 1170ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._expected_attrs = { 1180ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'event_type': event_type, 1190ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'event_result': event_result, 1200ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'version': version, 1210ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'previous_version': previous_version, 1220ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold } 123248108c1c925791d926105f42212b1033213a4dcGilad Arnold self._on_error = on_error 1240ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1250ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1260338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold @staticmethod 1270338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold def _attr_val_str(attr_val, helper_dict, default=None): 1280338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """Returns an enriched attribute value string, or default.""" 1290338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if not attr_val: 1300338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return default 1310338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1320338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold s = str(attr_val) 1330338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if helper_dict: 1340338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold s += ':%s' % helper_dict.get(attr_val, 'unknown') 1350338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1360338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return s 1370338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1380338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1390338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold def _attr_name_and_values(self, attr_name, expected_attr_val, 1400338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual_attr_val=None): 1410338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """Returns an attribute name, expected and actual value strings. 1420338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1430338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold This will return (name, expected, actual); the returned value for 1440338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual will be None if its respective input is None/empty. 1450338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1460338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """ 1470338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold helper_dict = self._ATTR_NAME_DICT_MAP.get(attr_name) 1480338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold expected_attr_val_str = self._attr_val_str(expected_attr_val, 1490338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold helper_dict, 1500338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold default='any') 1510338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual_attr_val_str = self._attr_val_str(actual_attr_val, helper_dict) 1520338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1530338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return attr_name, expected_attr_val_str, actual_attr_val_str 1540338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1550338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 156248108c1c925791d926105f42212b1033213a4dcGilad Arnold def _attrs_to_str(self, attrs_dict): 1570338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return ' '.join(['%s=%s' % 1580338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold self._attr_name_and_values(attr_name, attr_val)[0:2] 159248108c1c925791d926105f42212b1033213a4dcGilad Arnold for attr_name, attr_val in attrs_dict.iteritems()]) 160248108c1c925791d926105f42212b1033213a4dcGilad Arnold 161248108c1c925791d926105f42212b1033213a4dcGilad Arnold 162248108c1c925791d926105f42212b1033213a4dcGilad Arnold def __str__(self): 163248108c1c925791d926105f42212b1033213a4dcGilad Arnold return self._attrs_to_str(self._expected_attrs) 1640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1650ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1660ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def verify(self, actual_event): 1670ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verify the attributes of an actual event. 1680ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 169ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa @param actual_event: a dictionary containing event attributes 1700ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 171248108c1c925791d926105f42212b1033213a4dcGilad Arnold @return An error message, or None if all attributes as expected. 1720ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1730ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 174248108c1c925791d926105f42212b1033213a4dcGilad Arnold mismatched_attrs = [ 175248108c1c925791d926105f42212b1033213a4dcGilad Arnold attr_name for attr_name, expected_attr_val 176248108c1c925791d926105f42212b1033213a4dcGilad Arnold in self._expected_attrs.iteritems() 177248108c1c925791d926105f42212b1033213a4dcGilad Arnold if (expected_attr_val and 178248108c1c925791d926105f42212b1033213a4dcGilad Arnold not self._verify_attr(attr_name, expected_attr_val, 179248108c1c925791d926105f42212b1033213a4dcGilad Arnold actual_event.get(attr_name)))] 180248108c1c925791d926105f42212b1033213a4dcGilad Arnold if not mismatched_attrs: 181248108c1c925791d926105f42212b1033213a4dcGilad Arnold return None 182248108c1c925791d926105f42212b1033213a4dcGilad Arnold if callable(self._on_error): 183248108c1c925791d926105f42212b1033213a4dcGilad Arnold return self._on_error(self._expected_attrs, actual_event, 184248108c1c925791d926105f42212b1033213a4dcGilad Arnold mismatched_attrs) 185248108c1c925791d926105f42212b1033213a4dcGilad Arnold if self._on_error is None: 186248108c1c925791d926105f42212b1033213a4dcGilad Arnold return ('Received event (%s) does not match expectation (%s)' % 187248108c1c925791d926105f42212b1033213a4dcGilad Arnold (self._attrs_to_str(actual_event), self)) 188248108c1c925791d926105f42212b1033213a4dcGilad Arnold return self._on_error 1890ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1900ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1910ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def _verify_attr(self, attr_name, expected_attr_val, actual_attr_val): 1920ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies that an actual log event attributes matches expected on. 1930ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1940ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param attr_name: name of the attribute to verify 1950ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param expected_attr_val: expected attribute value 1960ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param actual_attr_val: actual attribute value 1970ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return True if actual value is present and matches, False otherwise. 1990ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2000ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 20145f02ae47134953169805d281992c9edf0019250Chris Sosa # None values are assumed to be missing and non-matching. 202f014ab424450fd595c347d905ac06ccf3d6faaddGilad Arnold if actual_attr_val is None: 2030338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.error('No value found for %s (expected %s)', 2040338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold *self._attr_name_and_values(attr_name, 2050338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold expected_attr_val)[0:2]) 20645f02ae47134953169805d281992c9edf0019250Chris Sosa return False 20745f02ae47134953169805d281992c9edf0019250Chris Sosa 20816e76893c34739649a751f42b3881b57620d665cGilad Arnold # We allow expected version numbers (e.g. 2940.0.0) to be contained in 20916e76893c34739649a751f42b3881b57620d665cGilad Arnold # actual values (2940.0.0-a1); this is necessary for the test to pass 21016e76893c34739649a751f42b3881b57620d665cGilad Arnold # with developer / non-release images. 21116e76893c34739649a751f42b3881b57620d665cGilad Arnold if (actual_attr_val == expected_attr_val or 21216e76893c34739649a751f42b3881b57620d665cGilad Arnold ('version' in attr_name and expected_attr_val in actual_attr_val)): 21316e76893c34739649a751f42b3881b57620d665cGilad Arnold return True 2140ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 21516e76893c34739649a751f42b3881b57620d665cGilad Arnold return False 2160ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2170ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 218248108c1c925791d926105f42212b1033213a4dcGilad Arnold def get_attrs(self): 219248108c1c925791d926105f42212b1033213a4dcGilad Arnold """Returns a dictionary of expected attributes.""" 220248108c1c925791d926105f42212b1033213a4dcGilad Arnold return dict(self._expected_attrs) 221248108c1c925791d926105f42212b1033213a4dcGilad Arnold 222248108c1c925791d926105f42212b1033213a4dcGilad Arnold 2230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass ExpectedUpdateEventChain(object): 2240ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Defines a chain of expected update events.""" 225248108c1c925791d926105f42212b1033213a4dcGilad Arnold def __init__(self): 226fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo self._expected_events_chain = [] 2270ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2280ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 229fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo def add_event(self, expected_events, timeout, on_timeout=None): 230248108c1c925791d926105f42212b1033213a4dcGilad Arnold """Adds an expected event to the chain. 231248108c1c925791d926105f42212b1033213a4dcGilad Arnold 232fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo @param expected_events: The ExpectedEvent, or a list thereof, to wait 233fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo for. If a list is passed, it will wait for *any* 234fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo of the provided events, but only one of those. 235248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param timeout: A timeout (in seconds) to wait for the event. 236248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param on_timeout: An error string to use if the event times out. If 237248108c1c925791d926105f42212b1033213a4dcGilad Arnold None, a generic message is used. 2380ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 239fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo if isinstance(expected_events, ExpectedUpdateEvent): 24016e76893c34739649a751f42b3881b57620d665cGilad Arnold expected_events = [expected_events] 241fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo self._expected_events_chain.append( 242fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo (expected_events, timeout, on_timeout)) 2430ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2440ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 245cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @staticmethod 246fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo def _format_event_with_timeout(expected_events, timeout): 247cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Returns a string representation of the event, with timeout.""" 248248108c1c925791d926105f42212b1033213a4dcGilad Arnold until = 'within %s seconds' % timeout if timeout else 'indefinitely' 249fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo return '%s, %s' % (' OR '.join(map(str, expected_events)), until) 2500ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2510ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2520ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __str__(self): 2530ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return ('[%s]' % 2540ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold ', '.join( 255fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo [self._format_event_with_timeout(expected_events, timeout) 256fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo for expected_events, timeout, _ 257fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo in self._expected_events_chain])) 2580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2600ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __repr__(self): 261fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo return str(self._expected_events_chain) 2620ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2630ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def verify(self, get_next_event): 2650ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies that an actual stream of events complies. 2660ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2670ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param get_next_event: a function returning the next event 2680ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 269ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify an event. 2700ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2710ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 272fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo for expected_events, timeout, on_timeout in self._expected_events_chain: 2730338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Expecting %s', 274fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo self._format_event_with_timeout(expected_events, 275248108c1c925791d926105f42212b1033213a4dcGilad Arnold timeout)) 276248108c1c925791d926105f42212b1033213a4dcGilad Arnold err_msg = self._verify_event_with_timeout( 277fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo expected_events, timeout, on_timeout, get_next_event) 278248108c1c925791d926105f42212b1033213a4dcGilad Arnold if err_msg is not None: 279248108c1c925791d926105f42212b1033213a4dcGilad Arnold logging.error('Failed expected event: %s', err_msg) 280248108c1c925791d926105f42212b1033213a4dcGilad Arnold raise ExpectedUpdateEventChainFailed(err_msg) 2810ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2820ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 283cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @staticmethod 284fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo def _verify_event_with_timeout(expected_events, timeout, on_timeout, 285248108c1c925791d926105f42212b1033213a4dcGilad Arnold get_next_event): 2860ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verify an expected event occurs within a given timeout. 2870ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 288fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo @param expected_events: the list of possible events expected next 289248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param timeout: specified in seconds 290248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param on_timeout: A string to return if timeout occurs, or None. 2910ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param get_next_event: function returning the next event in a stream 2920ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 293248108c1c925791d926105f42212b1033213a4dcGilad Arnold @return None if event complies, an error string otherwise. 2940ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2950ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 2960ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold base_timestamp = curr_timestamp = time.time() 2970ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold expired_timestamp = base_timestamp + timeout 2980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold while curr_timestamp <= expired_timestamp: 2990ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold new_event = get_next_event() 3000ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if new_event: 3010338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Event received after %s seconds', 3020338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold round(curr_timestamp - base_timestamp, 1)) 30316e76893c34739649a751f42b3881b57620d665cGilad Arnold results = [event.verify(new_event) for event in expected_events] 30416e76893c34739649a751f42b3881b57620d665cGilad Arnold return None if None in results else ' AND '.join(results) 3050ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3060ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # No new events, sleep for one second only (so we don't miss 3070ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # events at the end of the allotted timeout). 3080ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold time.sleep(1) 3090ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold curr_timestamp = time.time() 3100ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3110338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.error('Timeout expired') 312248108c1c925791d926105f42212b1033213a4dcGilad Arnold if on_timeout is None: 313248108c1c925791d926105f42212b1033213a4dcGilad Arnold return ('Waiting for event %s timed out after %d seconds' % 314fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo (' OR '.join(map(str, expected_events)), timeout)) 315248108c1c925791d926105f42212b1033213a4dcGilad Arnold return on_timeout 3160ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3170ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3180ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass UpdateEventLogVerifier(object): 3190ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies update event chains on a devserver update log.""" 32003901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold def __init__(self, event_log_url, url_request_timeout=None): 3210ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._event_log_url = event_log_url 32203901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold self._url_request_timeout = url_request_timeout 3230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._event_log = [] 3240ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._num_consumed_events = 0 3250ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3260ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 327fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo def verify_expected_events_chain(self, expected_event_chain): 328ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa """Verify a given event chain. 329ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa 330ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa @param expected_event_chain: instance of expected event chain. 331ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 332ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify the an 333ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa event. 334ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa """ 335ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa expected_event_chain.verify(self._get_next_log_event) 3360ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3370ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3380ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def _get_next_log_event(self): 3390ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Returns the next event in an event log. 3400ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3410ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold Uses the URL handed to it during initialization to obtain the host log 3420ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold from a devserver. If new events are encountered, the first of them is 3430ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold consumed and returned. 3440ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3450ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return The next new event in the host log, as reported by devserver; 34603901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold None if no such event was found or an error occurred. 3470ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3480ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 3490ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold # (Re)read event log from devserver, if necessary. 3500ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if len(self._event_log) <= self._num_consumed_events: 35103901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold try: 35203901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold if self._url_request_timeout: 35303901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold conn = urllib2.urlopen(self._event_log_url, 35403901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold timeout=self._url_request_timeout) 35503901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold else: 35603901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold conn = urllib2.urlopen(self._event_log_url) 35703901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold except urllib2.URLError, e: 3580338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.warning('Failed to read event log url: %s', e) 35903901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold return None 360a0261611f9be78ee9d456fd50bea81e9eda07c17Gilad Arnold except socket.timeout, e: 361a0261611f9be78ee9d456fd50bea81e9eda07c17Gilad Arnold logging.warning('Timed out reading event log url: %s', e) 362a0261611f9be78ee9d456fd50bea81e9eda07c17Gilad Arnold return None 36303901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold 3640ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold event_log_resp = conn.read() 3650ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold conn.close() 3660ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._event_log = json.loads(event_log_resp) 3670ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 36803901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold # Return next new event, if one is found. 3690ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if len(self._event_log) > self._num_consumed_events: 3707572b05fd3356b2ddf6866958e80c7885e44647bGilad Arnold new_event = { 3717572b05fd3356b2ddf6866958e80c7885e44647bGilad Arnold key: str(val) for key, val 3727572b05fd3356b2ddf6866958e80c7885e44647bGilad Arnold in self._event_log[self._num_consumed_events].iteritems() 3737572b05fd3356b2ddf6866958e80c7885e44647bGilad Arnold } 3740ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._num_consumed_events += 1 3750338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Consumed new event: %s', new_event) 3760ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return new_event 3770ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3780ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 379793344b359304c31d78197788b55cfbbe2636025Chris Sosaclass OmahaDevserverFailedToStart(error.TestError): 380793344b359304c31d78197788b55cfbbe2636025Chris Sosa """Raised when a omaha devserver fails to start.""" 381793344b359304c31d78197788b55cfbbe2636025Chris Sosa 382793344b359304c31d78197788b55cfbbe2636025Chris Sosa 3830ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass OmahaDevserver(object): 3840ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Spawns a test-private devserver instance.""" 385793344b359304c31d78197788b55cfbbe2636025Chris Sosa # How long to wait for a devserver to start. 38652c35724507ec105053d2af792fe161a627e05c1Alex Deymo _WAIT_FOR_DEVSERVER_STARTED_SECONDS = 30 387793344b359304c31d78197788b55cfbbe2636025Chris Sosa 388260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # How long to sleep (seconds) between checks to see if a devserver is up. 38903901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold _WAIT_SLEEP_INTERVAL = 1 3900ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3916f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # Max devserver execution time (seconds); used with timeout(1) to ensure we 3926f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # don't have defunct instances hogging the system. 3936f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold _DEVSERVER_TIMELIMIT_SECONDS = 12 * 60 * 60 394793344b359304c31d78197788b55cfbbe2636025Chris Sosa 395793344b359304c31d78197788b55cfbbe2636025Chris Sosa 396260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def __init__(self, omaha_host, devserver_dir, update_payload_staged_url): 3970ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Starts a private devserver instance, operating at Omaha capacity. 3980ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3990ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param omaha_host: host address where the devserver is spawned. 40003901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold @param devserver_dir: path to the devserver source directory 401ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param update_payload_staged_url: URL to provision for update requests. 4020ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 4030ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 404ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa if not update_payload_staged_url: 4050338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold raise error.TestError('Missing update payload url') 4060ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 4076c55bdb98e967675456a71a0971b81058536cac8Chris Sosa self._omaha_host = omaha_host 408260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid = 0 409260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_port = 0 # Determined later from devserver portfile. 4106c55bdb98e967675456a71a0971b81058536cac8Chris Sosa self._devserver_dir = devserver_dir 411ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._update_payload_staged_url = update_payload_staged_url 4126c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 4136c55bdb98e967675456a71a0971b81058536cac8Chris Sosa self._devserver_ssh = hosts.SSHHost(self._omaha_host, 4146c55bdb98e967675456a71a0971b81058536cac8Chris Sosa user=os.environ['USER']) 415260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 4163563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa # Temporary files for various devserver outputs. 4173563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_logfile = None 418238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo self._devserver_stdoutfile = None 4193563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_portfile = None 4203563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_pidfile = None 4213563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_static_dir = None 4223563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 4233563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 4243563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa def _cleanup_devserver_files(self): 4253563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa """Cleans up the temporary devserver files.""" 426238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo for filename in (self._devserver_logfile, self._devserver_stdoutfile, 427238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo self._devserver_portfile, self._devserver_pidfile): 428238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo if filename: 429238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo self._devserver_ssh.run('rm -f %s' % filename, 430238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo ignore_status=True) 4313563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 4323563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa if self._devserver_static_dir: 4333563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_ssh.run('rm -rf %s' % self._devserver_static_dir, 4343563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa ignore_status=True) 4353563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 436260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 4373563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa def _create_tempfile_on_devserver(self, label, dir=False): 4383563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa """Creates a temporary file/dir on the devserver and returns its path. 439260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 440260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @param label: Identifier for the file context (string, no whitespaces). 4413563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa @param dir: If True, create a directory instead of a file. 442260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 443260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @raises test.TestError: If we failed to invoke mktemp on the server. 444260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @raises OmahaDevserverFailedToStart: If tempfile creation failed. 445260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """ 446260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold remote_cmd = 'mktemp --tmpdir devserver-%s.XXXXXX' % label 4473563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa if dir: 4483563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa remote_cmd += ' --directory' 4493563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 450260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 451260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold result = self._devserver_ssh.run(remote_cmd, ignore_status=True) 452260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except error.AutoservRunError as e: 453260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._log_and_raise_remote_ssh_error(e) 454260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if result.exit_status != 0: 455260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold raise OmahaDevserverFailedToStart( 456260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'Could not create a temporary %s file on the devserver, ' 457a7412a90ffefac2b6314726b284af1b31d6bd797Alex Deymo 'error output: "%s"' % (label, result.stderr)) 458260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return result.stdout.strip() 459260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 460260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold @staticmethod 461260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _log_and_raise_remote_ssh_error(e): 462260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Logs failure to ssh remote, then raises a TestError.""" 463260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.debug('Failed to ssh into the devserver: %s', e) 464260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.error('If you are running this locally it means you did not ' 465260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'configure ssh correctly.') 466260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold raise error.TestError('Failed to ssh into the devserver: %s' % e) 467260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 468260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 469260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold def _read_int_from_devserver_file(self, filename): 470260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold """Reads and returns an integer value from a file on the devserver.""" 471260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold return int(self._get_devserver_file_content(filename).strip()) 4720ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 4736c55bdb98e967675456a71a0971b81058536cac8Chris Sosa 474793344b359304c31d78197788b55cfbbe2636025Chris Sosa def _wait_for_devserver_to_start(self): 475793344b359304c31d78197788b55cfbbe2636025Chris Sosa """Waits until the devserver starts within the time limit. 476793344b359304c31d78197788b55cfbbe2636025Chris Sosa 477260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold Infers and sets the devserver PID and serving port. 478260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 479793344b359304c31d78197788b55cfbbe2636025Chris Sosa Raises: 480793344b359304c31d78197788b55cfbbe2636025Chris Sosa OmahaDevserverFailedToStart: If the time limit is reached and we 481793344b359304c31d78197788b55cfbbe2636025Chris Sosa cannot connect to the devserver. 482793344b359304c31d78197788b55cfbbe2636025Chris Sosa """ 483260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # Compute the overall timeout. 484260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold deadline = time.time() + self._WAIT_FOR_DEVSERVER_STARTED_SECONDS 485260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 486260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # First, wait for port file to be filled and determine the server port. 48794b9ad4983cc735e162a3549c1628d08241b0d57Gilad Arnold logging.warning('Waiting for devserver to start up.') 488260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold while time.time() < deadline: 489260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold try: 490260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid = self._read_int_from_devserver_file( 491260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pidfile) 492260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_port = self._read_int_from_devserver_file( 493260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_portfile) 494260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.info('Devserver pid is %d, serving on port %d', 495260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_pid, self._devserver_port) 496260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold break 497260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold except Exception: # Couldn't read file or corrupt content. 498260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold time.sleep(self._WAIT_SLEEP_INTERVAL) 499260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold else: 50052c35724507ec105053d2af792fe161a627e05c1Alex Deymo try: 50152c35724507ec105053d2af792fe161a627e05c1Alex Deymo self._devserver_ssh.run_output('uptime') 50252c35724507ec105053d2af792fe161a627e05c1Alex Deymo except error.AutoservRunError as e: 50352c35724507ec105053d2af792fe161a627e05c1Alex Deymo logging.debug('Failed to run uptime on the devserver: %s', e) 50494b9ad4983cc735e162a3549c1628d08241b0d57Gilad Arnold raise OmahaDevserverFailedToStart( 505260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'The test failed to find the pid/port of the omaha ' 50652c35724507ec105053d2af792fe161a627e05c1Alex Deymo 'devserver after %d seconds. Check the dumped devserver ' 50752c35724507ec105053d2af792fe161a627e05c1Alex Deymo 'logs and devserver load for more information.' % 50852c35724507ec105053d2af792fe161a627e05c1Alex Deymo self._WAIT_FOR_DEVSERVER_STARTED_SECONDS) 509260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 510260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold # Check that the server is reponsding to network requests. 511260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold logging.warning('Waiting for devserver to accept network requests.') 512260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold url = 'http://%s' % self.get_netloc() 513260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold while time.time() < deadline: 514260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold if dev_server.DevServer.devserver_healthy(url, timeout_min=0.1): 515260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold break 516793344b359304c31d78197788b55cfbbe2636025Chris Sosa 517793344b359304c31d78197788b55cfbbe2636025Chris Sosa # TODO(milleral): Refactor once crbug.com/221626 is resolved. 518793344b359304c31d78197788b55cfbbe2636025Chris Sosa time.sleep(self._WAIT_SLEEP_INTERVAL) 519793344b359304c31d78197788b55cfbbe2636025Chris Sosa else: 520793344b359304c31d78197788b55cfbbe2636025Chris Sosa raise OmahaDevserverFailedToStart( 521793344b359304c31d78197788b55cfbbe2636025Chris Sosa 'The test failed to establish a connection to the omaha ' 522793344b359304c31d78197788b55cfbbe2636025Chris Sosa 'devserver it set up on port %d. Check the dumped ' 523260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold 'devserver logs for more information.' % 524260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold self._devserver_port) 525793344b359304c31d78197788b55cfbbe2636025Chris Sosa 526793344b359304c31d78197788b55cfbbe2636025Chris Sosa 5276c55bdb98e967675456a71a0971b81058536cac8Chris Sosa def start_devserver(self): 528793344b359304c31d78197788b55cfbbe2636025Chris Sosa """Starts the devserver and confirms it is up. 529793344b359304c31d78197788b55cfbbe2636025Chris Sosa 530793344b359304c31d78197788b55cfbbe2636025Chris Sosa Raises: 531260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold test.TestError: If we failed to spawn the remote devserver. 532793344b359304c31d78197788b55cfbbe2636025Chris Sosa OmahaDevserverFailedToStart: If the time limit is reached and we 533793344b359304c31d78197788b55cfbbe2636025Chris Sosa cannot connect to the devserver. 5346c55bdb98e967675456a71a0971b81058536cac8Chris Sosa """ 5352f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa update_payload_url_base, update_payload_path = self._split_url( 536ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._update_payload_staged_url) 5373563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 5383563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa # Allocate temporary files for various server outputs. 5393563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_logfile = self._create_tempfile_on_devserver('log') 540238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo self._devserver_stdoutfile = self._create_tempfile_on_devserver( 541238cff65701d1ea7ea9458baa7148f5a76f9b183Alex Deymo 'stdout') 5423563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_portfile = self._create_tempfile_on_devserver('port') 5433563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_pidfile = self._create_tempfile_on_devserver('pid') 5443563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa self._devserver_static_dir = self._create_tempfile_on_devserver( 5453563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 'static', dir=True) 5463563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa 5476f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # Invoke the Omaha/devserver on the remote server. Will attempt to kill 5486f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # it with a SIGTERM after a predetermined timeout has elapsed, followed 5496f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold # by SIGKILL if not dead within 30 seconds from the former signal. 5500ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold cmdlist = [ 5516f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold 'timeout', '-s', 'TERM', '-k', '30', 5526f36e954e1d73e961b8d47ebf4ec7d267c4307f4Gilad Arnold str(self._DEVSERVER_TIMELIMIT_SECONDS), 5536c55bdb98e967675456a71a0971b81058536cac8Chris Sosa '%s/devserver.py' % self._devserver_dir, 5540ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--payload=%s' % update_payload_path, 555260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--port=0', 556260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--pidfile=%s' % self._devserver_pidfile, 557260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--portfile=%s' % self._devserver_portfile, 558260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold '--logfile=%s' % self._devserver_logfile, 5590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--remote_payload', 5600ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--urlbase=%s' % update_payload_url_base, 5610ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--max_updates=1', 5620ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold '--host_log', 5633563042207623fbb9db02018156e8b5fa0e4c2c3Chris Sosa '--static_dir=%s' % self._devserver_static_dir, 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() 711f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if os_type == 'cros': 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] 89515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold return self._get_stateful_uri(build_uri) 8962f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 8972f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 898f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _update_via_test_payloads(self, omaha_host, payload_url, stateful_url, 899f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold clobber): 900cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Given the following update and stateful urls, update the DUT. 901cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 902cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold Only updates the rootfs/stateful if the respective url is provided. 903cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 904cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param omaha_host: If updating rootfs, redirect updates through this 905cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold host. Should be None iff payload_url is None. 906cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param payload_url: If set, the specified url to find the update 907cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold payload. 908cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param stateful_url: If set, the specified url to find the stateful 909cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold payload. 910cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param clobber: If True, do a clean install of stateful. 911cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """ 912cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold def perform_update(url, is_stateful): 913cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Perform a rootfs/stateful update using given URL. 914cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 915cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param url: URL to update from. 916cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @param is_stateful: Whether this is a stateful or rootfs update. 917cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """ 918cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if url: 919cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold updater = autoupdater.ChromiumOSUpdater(url, host=self._host) 920cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if is_stateful: 921cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold updater.update_stateful(clobber=clobber) 922cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold else: 9239e30d201214e586d185b497dea9a13a7e8d0495eGilad Arnold updater.update_image() 924cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 925cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold # We create a OmahaDevserver to redirect blah.bin to update/. This 926cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold # allows us to use any payload filename to serve an update. 927cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold temp_devserver = None 928cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold try: 929cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if payload_url: 930cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold temp_devserver = OmahaDevserver( 931260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold omaha_host, self._devserver_dir, payload_url) 932cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold temp_devserver.start_devserver() 933cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold payload_url = temp_devserver.get_update_url() 934cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 935cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold stateful_url = self._payload_to_update_url(stateful_url) 936cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 937cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold perform_update(payload_url, False) 938cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold perform_update(stateful_url, True) 939cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold finally: 940cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold if temp_devserver: 941260957d6079ee23ec6c9857a95fa183a78741b0bGilad Arnold temp_devserver.stop_devserver() 9422f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 9432f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 944f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _install_source_version(self, devserver_hostname, image_url, 945f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold stateful_url): 9462f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Prepare the specified host with the image given by the urls. 9472f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 948ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param devserver_hostname: If updating rootfs, redirect updates 949ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa through this host. Should be None iff 950ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa image_url is None. 9512f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param image_url: If set, the specified url to find the source image 9522f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa or full payload for the source image. 9532f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param stateful_url: If set, the specified url to find the stateful 9542f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa payload. 9552f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """ 9564cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold try: 9574cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # Reboot to get us into a clean state. 9584cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold self._host.reboot() 9594cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # Since we are installing the source image of the test, clobber 9604cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # stateful. 961f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._update_via_test_payloads(devserver_hostname, image_url, 96294694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold stateful_url, True) 9634cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold self._host.reboot() 9641b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold except OmahaDevserverFailedToStart as e: 9651b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold logging.fatal('Failed to start private devserver for installing ' 9661b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'the source image (%s) on the DUT', image_url) 9671b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold raise error.TestError( 9681b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'Failed to start private devserver for installing the ' 9691b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'source image on the DUT: %s' % e) 9701b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold except error.AutoservRunError as e: 9719b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold logging.fatal('Error re-imaging or rebooting the DUT with the ' 9729b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 'source image from %s', image_url) 9731b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold raise error.TestError('Failed to install the source image or ' 9741b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'reboot the DUT: %s' % e) 975f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 976f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 977f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _stage_artifacts_onto_devserver(self, test_conf): 9782f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Stages artifacts that will be used by the test onto the devserver. 9792f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 9802f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param test_conf: a dictionary containing test configuration values 9812f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 982f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return a StagedURLs tuple containing the staged urls. 983f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa """ 9840338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Staging images onto autotest devserver (%s)', 985f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._autotest_devserver.url()) 986f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 98715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_source_url = None 98815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_source_stateful_url = None 9899cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold try: 9909cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold source_payload_uri = test_conf['source_payload_uri'] 9919cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold except KeyError: 9929cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold # TODO(garnold) Remove legacy key support once control files on all 9939cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold # release branches have caught up. 9949cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold source_payload_uri = test_conf['source_image_uri'] 9954cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold if source_payload_uri: 99694694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold staged_source_url = self._stage_payload_by_uri(source_payload_uri) 9974cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold 9984cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # In order to properly install the source image using a full 9994cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # payload we'll also need the stateful update that comes with it. 10004cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # In general, tests may have their source artifacts in a different 10014cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # location than their payloads. This is determined by whether or 10024cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # not the source_archive_uri attribute is set; if it isn't set, 10034cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # then we derive it from the dirname of the source payload. 10044cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_archive_uri = test_conf.get('source_archive_uri') 10054cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold if source_archive_uri: 10064cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_stateful_uri = self._get_stateful_uri(source_archive_uri) 10072f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa else: 10084cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_stateful_uri = self._payload_to_stateful_uri( 10094cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_payload_uri) 1010fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold 10114cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold staged_source_stateful_url = self._stage_payload_by_uri( 101294694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold source_stateful_uri) 101315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 10144cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # Log source image URLs. 10154cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold logging.info('Source full payload from %s staged at %s', 10164cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_payload_uri, staged_source_url) 10174cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold if staged_source_stateful_url: 10184cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold logging.info('Source stateful update from %s staged at %s', 10194cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_stateful_uri, staged_source_stateful_url) 102015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 102115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_payload_uri = test_conf['target_payload_uri'] 102294694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold staged_target_url = self._stage_payload_by_uri(target_payload_uri) 102315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri = None 10240e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold staged_target_stateful_url = None 102515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_archive_uri = test_conf.get('target_archive_uri') 10260e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold if target_archive_uri: 10270e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold target_stateful_uri = self._get_stateful_uri(target_archive_uri) 10282f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa else: 10290e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold # Attempt to get the job_repo_url to find the stateful payload for 10300e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold # the target image. 10310e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold try: 10320e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold job_repo_url = self._host.lookup_job_repo_url() 10330e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold except KeyError: 10340e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold # If this failed, assume the stateful update is next to the 10350e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold # update payload. 103615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri = self._payload_to_stateful_uri( 103715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_payload_uri) 10380e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold else: 10390e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold _, devserver_label = tools.get_devserver_build_from_package_url( 10400e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold job_repo_url) 10410e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold staged_target_stateful_url = self._stage_payload( 104294694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold devserver_label, self._STATEFUL_UPDATE_FILENAME) 1043f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 10440e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold if not staged_target_stateful_url and target_stateful_uri: 104515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_stateful_url = self._stage_payload_by_uri( 104694694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold target_stateful_uri) 10472f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 1048fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold # Log target payload URLs. 104915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold logging.info('%s test payload from %s staged at %s', 105015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold test_conf['update_type'], target_payload_uri, 105115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_url) 10520338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Target stateful update from %s staged at %s', 105315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri or 'standard location', 105415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_stateful_url) 105515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 1056f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return self.StagedURLs(staged_source_url, staged_source_stateful_url, 1057f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold staged_target_url, staged_target_stateful_url) 1058f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1059f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1060c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen def _run_login_test(self, release_string): 1061c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen """Runs login_LoginSuccess test if it is supported by the release.""" 1062c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # Only do login tests with recent builds, since they depend on 1063c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # some binary compatibility with the build itself. 1064c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # '5116.0.0' -> ('5116', '0', '0') -> 5116 10657ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold if not release_string: 10667ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold logging.info('No release provided, skipping login test.') 10677ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold elif int(release_string.split('.')[0]) > self._LOGINABLE_MINIMUM_RELEASE: 1068c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen # Login, to prove we can before/after the update. 1069c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen logging.info('Attempting to login (release %s).', release_string) 1070c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1071c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen client_at = autotest.Autotest(self._host) 1072c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen client_at.run_test('login_LoginSuccess') 1073c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen else: 1074c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen logging.info('Not attempting login test because %s is older than ' 1075c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen '%d.', release_string, self._LOGINABLE_MINIMUM_RELEASE) 1076c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1077c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1078f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _start_perf_mon(self, bindir): 107931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """Starts monitoring performance and resource usage on a DUT. 108031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 108131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen Call _stop_perf_mon() with the returned PID to stop monitoring 108231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen and collect the results. 108331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1084f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param bindir: Directoy containing monitoring script. 1085f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1086f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return The PID of the newly created DUT monitoring process. 108731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """ 108831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # We can't assume much about the source image so we copy the 108931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # performance monitoring script to the DUT directly. 1090f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold path = os.path.join(bindir, 'update_engine_performance_monitor.py') 109131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen self._host.send_file(path, '/tmp') 109231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen cmd = 'python /tmp/update_engine_performance_monitor.py --start-bg' 109331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen return int(self._host.run(cmd).stdout) 109431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 109531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 109631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen def _stop_perf_mon(self, perf_mon_pid): 109731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """Stops monitoring performance and resource usage on a DUT. 109831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 109931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen @param perf_mon_pid: the PID returned from _start_perf_mon(). 110031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1101f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return Dictionary containing performance attributes, or None if 1102f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold unavailable. 110331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """ 110431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Gracefully handle problems with performance monitoring by 110531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # just returning None. 110631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen try: 110731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen cmd = ('python /tmp/update_engine_performance_monitor.py ' 110831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen '--stop-bg=%d') % perf_mon_pid 110931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen perf_json_txt = self._host.run(cmd).stdout 111031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen return json.loads(perf_json_txt) 111131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen except Exception as e: 111231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen logging.warning('Failed to parse output from ' 111331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'update_engine_performance_monitor.py: %s', e) 111431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen return None 111531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 111631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1117f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Interface overrides. 1118f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # 1119f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def initialize(self, autotest_devserver, devserver_dir): 1120f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._autotest_devserver = autotest_devserver 1121f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._devserver_dir = devserver_dir 1122f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1123f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1124f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def reboot_device(self): 1125f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._host.reboot() 1126f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1127f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1128f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def prep_artifacts(self, test_conf): 1129f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._staged_urls = self._stage_artifacts_onto_devserver(test_conf) 1130f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return self._staged_urls 1131f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1132f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1133f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def prep_device_for_update(self, source_release): 1134f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Install the source version onto the DUT. 1135f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if self._staged_urls.source_url: 11369b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold logging.info('Installing a source image on the DUT') 1137f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver_hostname = urlparse.urlparse( 1138f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._autotest_devserver.url()).hostname 1139f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._install_source_version(devserver_hostname, 1140f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._staged_urls.source_url, 1141f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._staged_urls.source_stateful_url) 1142f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1143f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Make sure we can login before the update. 1144f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._run_login_test(source_release) 1145f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1146f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1147f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def get_active_slot(self): 1148f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return self._host.run('rootdev -s').stdout.strip() 1149f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1150f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1151f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def start_update_perf(self, bindir): 1152f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if self._perf_mon_pid is None: 1153f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._perf_mon_pid = self._start_perf_mon(bindir) 1154f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1155f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1156f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def stop_update_perf(self): 1157f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold perf_data = None 1158f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if self._perf_mon_pid is not None: 1159f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold perf_data = self._stop_perf_mon(self._perf_mon_pid) 1160f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._perf_mon_pid = None 1161f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1162f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return perf_data 1163f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1164f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1165f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def trigger_update(self, omaha_devserver): 1166f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold updater = autoupdater.ChromiumOSUpdater( 1167f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold omaha_devserver.get_update_url(), host=self._host) 1168f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold updater.trigger_update() 1169f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1170f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1171f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def finalize_update(self): 1172f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._update_via_test_payloads( 117394694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold None, None, self._staged_urls.target_stateful_url, False) 1174f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1175f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1176f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def get_update_log(self, num_lines): 1177f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return self._host.run_output( 1178fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 'tail -n %d /var/log/update_engine.log' % num_lines, 1179fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold stdout_tee=None) 1180f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1181f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1182f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def check_device_after_update(self, target_release): 1183f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Make sure we can login after update. 1184f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._run_login_test(target_release) 1185f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1186f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1187b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnoldclass BrilloTestPlatform(TestPlatform): 1188b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold """A TestPlatform implementation for Brillo.""" 1189b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1190b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold _URL_DEFAULT_PORT = 80 1191b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold _DUT_LOCALHOST = '127.0.0.1' 1192b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1193b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def __init__(self, host): 1194b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold self._host = host 11959b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._autotest_devserver = None 11969b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._devserver_dir = None 11979b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._staged_urls = None 1198b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold self._forwarding_ports = set() 1199b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1200b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1201b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold @classmethod 1202b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold def _get_host_port(cls, url): 1203b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold """Returns the host and port values from a given URL. 1204b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1205b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold @param url: The URL from which the values are extracted. 1206b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1207b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold @return A pair consisting of the host and port strings. 1208b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold """ 1209b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold host, _, port = urlparse.urlsplit(url).netloc.partition(':') 1210b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold return host, port or str(cls._URL_DEFAULT_PORT) 1211b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1212b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1213b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold def _install_rev_forwarding(self, port=None): 1214b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold """Installs reverse forwarding rules via ADB. 12159b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 1216b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold @param port: The TCP port we want forwarded; if None, installs all 1217b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold previously configured ports. 1218b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold """ 1219b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold ports = self._forwarding_ports if port is None else [port] 1220b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold for port in ports: 1221b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold port_spec = 'tcp:%s' % port 1222b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._host.add_forwarding(port_spec, port_spec, reverse=True) 1223b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1224b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1225b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold def _add_rev_forwarding(self, url): 1226b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold """Configures reverse port forwarding and adjusts the given URL. 1227b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1228b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold This extracts the port from the URL, adds it to the set of configured 1229b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold forwarding ports, installs it to the DUT, then returns the adjusted URL 1230b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold for use by the DUT. 1231b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1232b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold @param url: The URL for which we need to establish forwarding. 1233b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1234b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold @return: The adjusted URL for use on the DUT. 12359b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold """ 12369b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold if url: 1237b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold host, port = self._get_host_port(url) 1238b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold if port not in self._forwarding_ports: 1239b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._forwarding_ports.add(port) 1240b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._install_rev_forwarding(port=port) 1241b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold url = url.replace(host, self._DUT_LOCALHOST, 1) 1242b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold return url 12439b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 12449b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 1245b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold def _remove_rev_forwarding(self, url=None): 1246b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold """Removes a reverse port forwarding. 1247b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1248b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold @param url: The URL for which forwarding was established; if None, 1249b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold removes all previously configured ports. 1250b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold """ 1251b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold ports = set() 1252b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold if url is None: 1253b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold ports.update(self._forwarding_ports) 1254b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold else: 1255b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold _, port = self._get_host_port(url) 1256b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold if port in self._forwarding_ports: 1257b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold ports.add(port) 1258b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1259b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold # TODO(garnold) Enable once ADB port removal is fixed (b/24771474): 1260b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold # for port in ports: 1261b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold # self._host.remove_forwarding(src='tcp:%s' % port, reverse=True) 1262b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold 1263b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._forwarding_ports.difference_update(ports) 1264b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1265b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 12669b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold def _install_source_version(self, devserver_hostname, payload_url): 12679b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold """Installs a source version onto the test device. 12689b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 12699b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold @param devserver_hostname: Redirect updates through this host. 12709b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold @param payload_url: URL of staged payload for installing a source image. 12719b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold """ 12729b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold try: 12739b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold # Start a private Omaha server and update the DUT. 12749b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold temp_devserver = None 1275b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold url = None 12769b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold try: 12779b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold temp_devserver = OmahaDevserver( 12789b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold devserver_hostname, self._devserver_dir, payload_url) 12799b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold temp_devserver.start_devserver() 1280b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold url = self._add_rev_forwarding(temp_devserver.get_update_url()) 12819b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold updater = autoupdater.BrilloUpdater(url, host=self._host) 12829b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold updater.update_image() 12839b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold finally: 1284b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold if url: 1285b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._remove_rev_forwarding(url) 12869b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold if temp_devserver: 12879b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold temp_devserver.stop_devserver() 12889b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 12899b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold # Reboot the DUT. 12909b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self.reboot_device() 12919b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold except OmahaDevserverFailedToStart as e: 12929b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold logging.fatal('Failed to start private devserver for installing ' 12939b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 'the source payload (%s) on the DUT', payload_url) 12949b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold raise error.TestError( 12959b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 'Failed to start private devserver for installing the ' 12969b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 'source image on the DUT: %s' % e) 12979b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold except error.AutoservRunError as e: 12989b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold logging.fatal('Error re-imaging or rebooting the DUT with the ' 12999b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 'source image from %s', payload_url) 13009b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold raise error.TestError('Failed to install the source image or ' 13019b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 'reboot the DUT: %s' % e) 13029b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 13039b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold 1304b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold # Interface overrides. 1305b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold # 1306b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def initialize(self, autotest_devserver, devserver_dir): 13079b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._autotest_devserver = autotest_devserver 13089b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._devserver_dir = devserver_dir 1309b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1310b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1311b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def reboot_device(self): 1312b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold self._host.reboot() 1313b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._install_rev_forwarding() 1314b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1315b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1316b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def prep_artifacts(self, test_conf): 1317b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold # TODO(garnold) Currently we don't stage anything and assume that the 1318b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold # provided URLs are of pre-staged payloads. We should implement staging 1319b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold # support once a release scheme for Brillo is finalized. 13209b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._staged_urls = self.StagedURLs( 1321b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._add_rev_forwarding(test_conf['source_payload_uri']), None, 1322b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._add_rev_forwarding(test_conf['target_payload_uri']), None) 13239b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold return self._staged_urls 1324b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1325b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1326b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def prep_device_for_update(self, source_release): 13279b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold # Install the source version onto the DUT. 13289b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold if self._staged_urls.source_url: 13299b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold logging.info('Installing a source image on the DUT') 13309b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold devserver_hostname = urlparse.urlparse( 13319b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._autotest_devserver.url()).hostname 13329b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._install_source_version(devserver_hostname, 13339b976d77f77c94733ab711c15db4e08528926d46Gilad Arnold self._staged_urls.source_url) 1334b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1335b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1336b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def get_active_slot(self): 1337b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold return self._host.run('rootdev -s /system').stdout.strip() 1338b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1339b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1340b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def start_update_perf(self, bindir): 1341b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold pass 1342b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1343b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1344b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def stop_update_perf(self): 1345b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold pass 1346b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1347b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1348b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def trigger_update(self, omaha_devserver): 1349b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold url = self._add_rev_forwarding(omaha_devserver.get_update_url()) 1350b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold updater = autoupdater.BrilloUpdater(url, host=self._host) 1351b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold updater.trigger_update() 1352b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1353b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1354b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def finalize_update(self): 1355b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold pass 1356b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1357b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1358b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def get_update_log(self, num_lines): 1359b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold return self._host.run_output( 1360fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 'logcat -d -s update_engine | tail -n %d' % num_lines, 1361fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold stdout_tee=None) 1362b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1363b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1364b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold def check_device_after_update(self, target_release): 1365b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold self._remove_rev_forwarding() 1366b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold # TODO(garnold) Port forwarding removal is broken in ADB (b/24771474). 1367b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold # Instead we reboot the device, which has the side-effect of flushing 1368b90740522d88ed5770e512502aaa396710a54b1dGilad Arnold # all forwarding rules. Once fixed, the following should be removed. 136903322d32f30c95159e0651709a87132fa8b12bb4Gilad Arnold self.reboot_device() 1370b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1371b7ebf3322b6e63e0286ae27ed2c6d3b79655ff20Gilad Arnold 1372f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnoldclass autoupdate_EndToEndTest(test.test): 1373f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Complete update test between two Chrome OS releases. 1374f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1375f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold Performs an end-to-end test of updating a ChromeOS device from one version 1376f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold to another. The test performs the following steps: 1377f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1378f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1. Stages the source (full) and target update payload on the central 1379f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver. 1380f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 2. Spawns a private Omaha-like devserver instance, configured to return 1381f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold the target (update) payload URL in response for an update check. 1382f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 3. Reboots the DUT. 1383f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 4. Installs a source image on the DUT (if provided) and reboots to it. 1384f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 5. Triggers an update check at the DUT. 1385f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 6. Watches as the DUT obtains an update and applies it. 1386f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 7. Reboots and repeats steps 5-6, ensuring that the next update check 1387f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold shows the new image version. 1388f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1389f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold Some notes on naming: 1390f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver: Refers to a machine running the Chrome OS Update Devserver. 1391f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold autotest_devserver: An autotest wrapper to interact with a devserver. 1392f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold Can be used to stage artifacts to a devserver. While 1393f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold this can also be used to update a machine, we do not 1394f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold use it for that purpose in this test as we manage 1395f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold updates with out own devserver instances (see below). 1396f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold omaha_devserver: This test's wrapper of a devserver running for the 1397f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold purposes of emulating omaha. This test controls the 1398f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold lifetime of this devserver instance and is separate 1399f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold from the autotest lab's devserver's instances which are 1400f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold only used for staging and hosting artifacts (because they 1401f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold scale). These are run on the same machines as the actual 1402f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold autotest devservers which are used for staging but on 1403f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold different ports. 1404f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold *staged_url's: In this case staged refers to the fact that these items 1405f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold are available to be downloaded statically from these urls 1406f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold e.g. 'localhost:8080/static/my_file.gz'. These are usually 1407f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold given after staging an artifact using a autotest_devserver 1408f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold though they can be re-created given enough assumptions. 1409f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold *update_url's: Urls refering to the update RPC on a given omaha devserver. 1410f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold Since we always use an instantiated omaha devserver to run 1411f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold updates, these will always reference an existing instance 1412f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold of an omaha devserver that we just created for the purposes 1413f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold of updating. 1414f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver_hostname: At the start of each test, we choose a devserver 1415f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold machine in the lab for the test. We use the devserver 1416f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold instance there (access by autotest_devserver) to stage 1417f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold artifacts. However, we also use the same host to start 1418f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold omaha devserver instances for updating machines with 1419f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold (that reference the staged paylaods on the autotest 1420f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver instance). This hostname refers to that 1421f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold machine we are using (since it's always the same for 1422f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold both staging/omaha'ing). 1423f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1424f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 1425f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold version = 1 1426f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1427f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Timeout periods, given in seconds. 1428f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_AFTER_SHUTDOWN_SECONDS = 10 1429f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_AFTER_UPDATE_SECONDS = 20 1430f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_USB_INSTALL_SECONDS = 4 * 60 1431f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_MP_RECOVERY_SECONDS = 8 * 60 1432f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_INITIAL_UPDATE_CHECK_SECONDS = 12 * 60 1433f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # TODO(sosa): Investigate why this needs to be so long (this used to be 1434f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # 120 and regressed). 1435f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_DOWNLOAD_STARTED_SECONDS = 4 * 60 1436f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_DOWNLOAD_COMPLETED_SECONDS = 10 * 60 1437f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_UPDATE_COMPLETED_SECONDS = 4 * 60 1438f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_UPDATE_CHECK_AFTER_REBOOT_SECONDS = 15 * 60 1439f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _DEVSERVER_HOSTLOG_REQUEST_TIMEOUT_SECONDS = 30 1440f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1441a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold # Logs and their whereabouts. 1442a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold _WHERE_UPDATE_LOG = ('update_engine log (in sysinfo or on the DUT, also ' 1443a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'included in the test log)') 1444a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold _WHERE_OMAHA_LOG = 'Omaha-devserver log (included in the test log)' 1445a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1446f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1447f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def initialize(self): 1448f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Sets up variables that will be used by test.""" 1449f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._host = None 1450f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._omaha_devserver = None 1451a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._source_image_installed = False 1452f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1453f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._devserver_dir = global_config.global_config.get_config_value( 1454f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 'CROS', 'devserver_dir', default=None) 1455f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if self._devserver_dir is None: 1456f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise error.TestError( 1457f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 'Path to devserver source tree not provided; please define ' 1458f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 'devserver_dir under [CROS] in your shadow_config.ini') 1459f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1460f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1461f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def cleanup(self): 1462f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Kill the omaha devserver if it's still around.""" 1463f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if self._omaha_devserver: 1464f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._omaha_devserver.stop_devserver() 1465f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1466f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._omaha_devserver = None 1467f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1468f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1469f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _dump_update_engine_log(self, test_platform): 1470f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Dumps relevant AU error log.""" 1471f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold try: 1472fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold error_log = test_platform.get_update_log(80) 1473fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold logging.error('Dumping snippet of update_engine log:\n%s', 1474fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold snippet(error_log)) 1475f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold except Exception: 1476f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Mute any exceptions we get printing debug logs. 1477f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold pass 1478f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1479f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 148031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen def _report_perf_data(self, perf_data): 148131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """Reports performance and resource data. 148231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1483f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold Currently, performance attributes are expected to include 'rss_peak' 1484f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold (peak memory usage in bytes). 1485f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1486f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param perf_data: A dictionary containing performance attributes. 148731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """ 148831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen rss_peak = perf_data.get('rss_peak') 148931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen if rss_peak: 149031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen rss_peak_kib = rss_peak / 1024 149131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen logging.info('Peak memory (RSS) usage on DUT: %d KiB', rss_peak_kib) 149231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen self.output_perf_value(description='mem_usage_peak', 149331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen value=int(rss_peak_kib), 149431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen units='KiB', 149531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen higher_is_better=False) 149631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen else: 149731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen logging.warning('No rss_peak key in JSON returned by ' 149831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'update_engine_performance_monitor.py') 149931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 150031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1501a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_initial_check(self, expected, actual, mismatched_attrs): 1502a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'version' in mismatched_attrs: 1503a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold err_msg = ('Initial update check was received but the reported ' 1504a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'version is different from what was expected.') 1505a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if self._source_image_installed: 1506a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold err_msg += (' The source payload we installed was probably ' 1507a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'incorrect or corrupt.') 1508a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold else: 1509a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold err_msg += (' The DUT is probably not running the correct ' 1510a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'source image.') 1511a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return err_msg 1512a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1513a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return 'A test bug occurred; inspect the test log.' 1514a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1515a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1516a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_intermediate(self, expected, actual, mismatched_attrs, action, 1517a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold problem): 1518a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'event_result' in mismatched_attrs: 15190ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold event_result = actual.get('event_result') 15200ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold reported = (('different than expected (%s)' % 15210ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold EVENT_RESULT_DICT[event_result]) 15220ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold if event_result else 'missing') 15230ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold return ('The updater reported result code is %s. This could be an ' 15240ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'updater bug or a connectivity problem; check the %s. For ' 15250ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'a detailed log of update events, check the %s.' % 15260ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold (reported, self._WHERE_UPDATE_LOG, self._WHERE_OMAHA_LOG)) 1527a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'event_type' in mismatched_attrs: 15280ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold event_type = actual.get('event_type') 15290ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold reported = ('different (%s)' % EVENT_TYPE_DICT[event_type] 15300ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold if event_type else 'missing') 15310ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold return ('Expected the updater to %s (%s) but received event type ' 15320ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'is %s. This could be an updater %s; check the ' 1533a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold '%s. For a detailed log of update events, check the %s.' % 15340ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold (action, EVENT_TYPE_DICT[expected['event_type']], reported, 15350ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold problem, self._WHERE_UPDATE_LOG, self._WHERE_OMAHA_LOG)) 1536a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'version' in mismatched_attrs: 1537a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('The updater reported an unexpected version despite ' 1538a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'previously reporting the correct one. This is most likely ' 1539a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'a bug in update engine; check the %s.' % 1540a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WHERE_UPDATE_LOG) 1541a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1542a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return 'A test bug occurred; inspect the test log.' 1543a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1544a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1545a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_download_started(self, expected, actual, mismatched_attrs): 1546a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return self._error_intermediate(expected, actual, mismatched_attrs, 1547a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'begin downloading', 1548a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'bug, crash or provisioning error') 1549a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1550a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1551a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_download_finished(self, expected, actual, mismatched_attrs): 1552a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return self._error_intermediate(expected, actual, mismatched_attrs, 1553a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'finish downloading', 'bug or crash') 1554a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1555a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1556a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_update_complete(self, expected, actual, mismatched_attrs): 1557a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return self._error_intermediate(expected, actual, mismatched_attrs, 1558a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'complete the update', 'bug or crash') 1559a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1560a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 156116e76893c34739649a751f42b3881b57620d665cGilad Arnold def _error_reboot_after_update(self, expected, actual, mismatched_attrs): 1562a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'event_result' in mismatched_attrs: 15630ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold event_result = actual.get('event_result') 15640ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold reported = ('different (%s)' % EVENT_RESULT_DICT[event_result] 15650ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold if event_result else 'missing') 1566a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('The updater was expected to reboot (%s) but reported ' 15670ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'result code is %s. This could be a failure to reboot, an ' 15680ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'updater bug or a connectivity problem; check the %s and ' 15690ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'the system log. For a detailed log of update events, ' 15700ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'check the %s.' % 15710ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold (EVENT_RESULT_DICT[expected['event_result']], reported, 1572a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WHERE_UPDATE_LOG, self._WHERE_OMAHA_LOG)) 1573a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'event_type' in mismatched_attrs: 15740ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold event_type = actual.get('event_type') 15750ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold reported = ('different (%s)' % EVENT_TYPE_DICT[event_type] 15760ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold if event_type else 'missing') 1577a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('Expected to successfully reboot into the new image (%s) ' 15780ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'but received event type is %s. This probably means that ' 15790ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'the new image failed to verify after reboot, possibly ' 15800ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'because the payload is corrupt. This might also be an ' 15810ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'updater bug or crash; check the %s. For a detailed log of ' 15820ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'update events, check the %s.' % 15830ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold (EVENT_TYPE_DICT[expected['event_type']], reported, 1584a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WHERE_UPDATE_LOG, self._WHERE_OMAHA_LOG)) 1585a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'version' in mismatched_attrs: 1586a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('The DUT rebooted after the update but reports a different ' 1587a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'image version than the one expected. This probably means ' 1588a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'that the payload we applied was incorrect or corrupt.') 1589a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'previous_version' in mismatched_attrs: 1590a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('The DUT rebooted after the update and reports the ' 1591a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'expected version. However, it reports a previous version ' 1592a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'that is different from the one previously reported. This ' 1593a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'is most likely a bug in update engine; check the %s.' % 1594a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WHERE_UPDATE_LOG) 1595a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1596a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return 'A test bug occurred; inspect the test log.' 1597a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1598a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1599a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _timeout_err(self, desc, timeout, event_type=None): 1600a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if event_type is not None: 1601a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold desc += ' (%s)' % EVENT_TYPE_DICT[event_type] 1602a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('Failed to receive %s within %d seconds. This could be a ' 1603a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'problem with the updater or a connectivity issue. For more ' 1604a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'details, check the %s.' % 1605a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold (desc, timeout, self._WHERE_UPDATE_LOG)) 1606a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1607a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1608f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def run_update_test(self, test_platform, test_conf): 1609ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Runs the actual update test once preconditions are met. 16100ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1611f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param test_platform: TestPlatform implementation. 1612ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param test_conf: A dictionary containing test configuration values 16130ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1614ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify an update 1615ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa event. 16160ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 1617c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1618f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Record the active root partition. 1619f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold source_active_slot = test_platform.get_active_slot() 1620f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold logging.info('Source active slot: %s', source_active_slot) 16210ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 16227ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold source_release = test_conf['source_release'] 16237ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold target_release = test_conf['target_release'] 16247ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold 162531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Start the performance monitoring process on the DUT. 1626f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform.start_update_perf(self.bindir) 162731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen try: 162831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Trigger an update. 1629f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform.trigger_update(self._omaha_devserver) 16300ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 163131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Track update progress. 163231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen omaha_netloc = self._omaha_devserver.get_netloc() 163331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen omaha_hostlog_url = urlparse.urlunsplit( 163431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen ['http', omaha_netloc, '/api/hostlog', 163531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 'ip=' + self._host.ip, '']) 163631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen logging.info('Polling update progress from omaha/devserver: %s', 163731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen omaha_hostlog_url) 163831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen log_verifier = UpdateEventLogVerifier( 163931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen omaha_hostlog_url, 164031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen self._DEVSERVER_HOSTLOG_REQUEST_TIMEOUT_SECONDS) 164131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 164231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Verify chain of events in a successful update process. 1643248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain = ExpectedUpdateEventChain() 1644248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain.add_event( 1645248108c1c925791d926105f42212b1033213a4dcGilad Arnold ExpectedUpdateEvent( 16467ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold version=source_release, 1647a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_error=self._error_initial_check), 1648a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_INITIAL_UPDATE_CHECK_SECONDS, 1649a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_timeout=self._timeout_err( 1650a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'an initial update check', 1651a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_INITIAL_UPDATE_CHECK_SECONDS)) 1652248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain.add_event( 1653248108c1c925791d926105f42212b1033213a4dcGilad Arnold ExpectedUpdateEvent( 1654248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_type=EVENT_TYPE_DOWNLOAD_STARTED, 1655248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_result=EVENT_RESULT_SUCCESS, 16567ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold version=source_release, 1657a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_error=self._error_download_started), 1658a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_DOWNLOAD_STARTED_SECONDS, 1659a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_timeout=self._timeout_err( 1660a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'a download started notification', 1661a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_DOWNLOAD_STARTED_SECONDS, 1662a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold event_type=EVENT_TYPE_DOWNLOAD_STARTED)) 1663248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain.add_event( 1664248108c1c925791d926105f42212b1033213a4dcGilad Arnold ExpectedUpdateEvent( 1665248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_type=EVENT_TYPE_DOWNLOAD_FINISHED, 1666248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_result=EVENT_RESULT_SUCCESS, 16677ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold version=source_release, 1668a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_error=self._error_download_finished), 1669a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_DOWNLOAD_COMPLETED_SECONDS, 1670a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_timeout=self._timeout_err( 1671a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'a download finished notification', 1672a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_DOWNLOAD_COMPLETED_SECONDS, 1673a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold event_type=EVENT_TYPE_DOWNLOAD_FINISHED)) 1674248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain.add_event( 1675248108c1c925791d926105f42212b1033213a4dcGilad Arnold ExpectedUpdateEvent( 1676248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_type=EVENT_TYPE_UPDATE_COMPLETE, 1677248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_result=EVENT_RESULT_SUCCESS, 16787ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold version=source_release, 1679a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_error=self._error_update_complete), 1680a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_UPDATE_COMPLETED_SECONDS, 1681a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_timeout=self._timeout_err( 1682a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'an update complete notification', 1683a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_UPDATE_COMPLETED_SECONDS, 1684a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold event_type=EVENT_TYPE_UPDATE_COMPLETE)) 168531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1686fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo log_verifier.verify_expected_events_chain(chain) 168731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 168831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Wait after an update completion (safety margin). 168931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen _wait(self._WAIT_AFTER_UPDATE_SECONDS, 'after update completion') 169031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen finally: 169131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Terminate perf monitoring process and collect its output. 1692f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold perf_data = test_platform.stop_update_perf() 169331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen if perf_data: 169431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen self._report_perf_data(perf_data) 1695f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 16964cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # Only update the stateful partition (the test updated the rootfs). 1697f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform.finalize_update() 16984cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold 1699f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # Reboot the DUT after the update. 1700bacc35bdb2fb44b0a760c05d364854cd92fb3f98Gilad Arnold test_platform.reboot_device() 17010ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1702f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # Trigger a second update check (again, test vs MP). 1703f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform.trigger_update(self._omaha_devserver) 17040ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1705f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # Observe post-reboot update check, which should indicate that the 1706f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa # image version has been updated. 1707248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain = ExpectedUpdateEventChain() 1708fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo expected_events = [ 1709fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo ExpectedUpdateEvent( 1710fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo event_type=EVENT_TYPE_UPDATE_COMPLETE, 1711fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo event_result=EVENT_RESULT_SUCCESS_REBOOT, 1712fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo version=target_release, 1713fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo previous_version=source_release, 1714fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo on_error=self._error_reboot_after_update), 1715fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo # Newer versions send a "rebooted_after_update" message after reboot 1716fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo # with the previous version instead of another "update_complete". 1717fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo ExpectedUpdateEvent( 1718fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo event_type=EVENT_TYPE_REBOOTED_AFTER_UPDATE, 1719fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo event_result=EVENT_RESULT_SUCCESS, 1720fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo version=target_release, 1721fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo previous_version=source_release, 1722fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo on_error=self._error_reboot_after_update), 1723fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo ] 1724248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain.add_event( 1725fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo expected_events, 1726a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_UPDATE_CHECK_AFTER_REBOOT_SECONDS, 1727a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_timeout=self._timeout_err( 1728a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'a successful reboot notification', 1729a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_UPDATE_CHECK_AFTER_REBOOT_SECONDS, 1730a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold event_type=EVENT_TYPE_UPDATE_COMPLETE)) 1731ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1732fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo log_verifier.verify_expected_events_chain(chain) 1733f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1734f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Make sure we're using a different slot after the update. 1735f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold target_active_slot = test_platform.get_active_slot() 1736f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if target_active_slot == source_active_slot: 17371b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold err_msg = 'The active image slot did not change after the update.' 17387ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold if None in (source_release, target_release): 17397ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold err_msg += (' The DUT likely rebooted into the old image, which ' 17407ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold 'probably means that the payload we applied was ' 17417ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold 'corrupt. But since we did not check the source ' 17427ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold 'and/or target version we cannot say for sure.') 17437ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold elif source_release == target_release: 17441b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold err_msg += (' Given that the source and target versions are ' 17451b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'identical, the DUT likely rebooted into the old ' 17461b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'image. This probably means that the payload we ' 17471b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'applied was corrupt.') 17481b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold else: 17491b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold err_msg += (' This is strange since the DUT reported the ' 17501b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'correct target version. This is probably a system ' 17511b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'bug; check the DUT system log.') 17521b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold raise error.TestFail(err_msg) 17530338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1754f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold logging.info('Target active slot changed as expected: %s', 1755f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold target_active_slot) 1756eb300ac8af429e51f751b95ce375636fbb649e37Gilad Arnold 17570338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Update successful, test completed') 17580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1759ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 17609cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold # TODO(garnold) Remove the use_servo argument once control files on all 17619cd891a18dcdeb1dd5f544322dd64f8f1845c6a6Gilad Arnold # release branches have caught up. 17624cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold def run_once(self, host, test_conf, use_servo=False): 1763ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Performs a complete auto update test. 1764ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1765ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param host: a host object representing the DUT 1766ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param test_conf: a dictionary containing test configuration values 17674cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold @param use_servo: DEPRECATED 1768ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1769ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raise error.TestError if anything went wrong with setting up the test; 1770ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa error.TestFail if any part of the test has failed. 1771ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1772ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """ 1773f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 1774ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._host = host 1775ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1776009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # Find a devserver to use. We first try to pick a devserver with the 1777009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # least load. In case all devservers' load are higher than threshold, 1778009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # fall back to the old behavior by picking a devserver based on the 1779009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # payload URI, with which ImageServer.resolve will return a random 1780009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # devserver based on the hash of the URI. 17814e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi least_loaded_devserver = dev_server.get_least_loaded_devserver() 17824e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi if least_loaded_devserver: 17834e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi logging.debug('Choose the least loaded devserver: %s', 17844e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi least_loaded_devserver) 17854e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi autotest_devserver = dev_server.ImageServer(least_loaded_devserver) 17864e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi else: 1787009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi logging.warning('No devserver meets the maximum load requirement. ' 1788009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi 'Pick a random devserver to use.') 1789009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi autotest_devserver = dev_server.ImageServer.resolve( 1790009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi test_conf['target_payload_uri']) 1791ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa devserver_hostname = urlparse.urlparse( 1792ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver.url()).hostname 1793d874a4d63dacfb6e8a74466eab5160e940aaa690Dan Shi counter_key = dev_server.ImageServer.create_stats_str( 1794d874a4d63dacfb6e8a74466eab5160e940aaa690Dan Shi 'paygen', devserver_hostname, artifacts=None) 1795d874a4d63dacfb6e8a74466eab5160e940aaa690Dan Shi metadata = {'devserver': devserver_hostname, 1796d874a4d63dacfb6e8a74466eab5160e940aaa690Dan Shi '_type': 'devserver_paygen'} 1797d874a4d63dacfb6e8a74466eab5160e940aaa690Dan Shi metadata.update(test_conf) 1798d874a4d63dacfb6e8a74466eab5160e940aaa690Dan Shi autotest_stats.Counter(counter_key, metadata=metadata).increment() 1799ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1800f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Obtain a test platform implementation. 1801f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform = TestPlatform.create(host) 1802f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform.initialize(autotest_devserver, self._devserver_dir) 1803f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1804ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa # Stage source images and update payloads onto a devserver. 1805f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold staged_urls = test_platform.prep_artifacts(test_conf) 1806a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._source_image_installed = bool(staged_urls.source_url) 1807ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1808f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Prepare the DUT (install source version etc). 1809f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform.prep_device_for_update(test_conf['source_release']) 1810ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1811ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._omaha_devserver = OmahaDevserver( 1812f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver_hostname, self._devserver_dir, 1813f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold staged_urls.target_url) 1814ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._omaha_devserver.start_devserver() 1815c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1816ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa try: 1817f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self.run_update_test(test_platform, test_conf) 1818ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa except ExpectedUpdateEventChainFailed: 1819f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._dump_update_engine_log(test_platform) 1820ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa raise 1821f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 1822f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform.check_device_after_update(test_conf['target_release']) 1823