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 53f9543109fc26571607da554e285eaf069ab2d51David Haddockfrom datetime import datetime, timedelta 62f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosaimport collections 70ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldimport json 80ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldimport logging 96c55bdb98e967675456a71a0971b81058536cac8Chris Sosaimport os 1015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnoldimport time 110ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldimport urlparse 1203901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold 13a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddockfrom autotest_lib.client.common_lib import error 14a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddockfrom autotest_lib.client.common_lib.cros import dev_server 15a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddockfrom autotest_lib.server import autotest, test 162f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosafrom autotest_lib.server.cros.dynamic_suite import tools 170ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 180ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 19a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddockdef snippet(text): 20a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock """Returns the text with start/end snip markers around it. 210ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 22a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock @param text: The snippet text. 230ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 24a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock @return The text with start/end snip markers around it. 25a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock """ 26a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock snip = '---8<---' * 10 27a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock start = '-- START -' 28a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock end = '-- END -' 29a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock return ('%s%s\n%s\n%s%s' % 30a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock (start, snip[len(start):], text, end, snip[len(end):])) 31ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 32aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid HaddockUPDATE_ENGINE_PERF_PATH = '/mnt/stateful_partition/unencrypted/preserve' 33aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid HaddockUPDATE_ENGINE_PERF_SCRIPT = 'update_engine_performance_monitor.py' 34aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid HaddockUPDATE_ENGINE_PERF_RESULTS_FILE = 'perf_data_results.json' 35ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 360338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold# Update event types. 370338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_DOWNLOAD_COMPLETE = '1' 380338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_INSTALL_COMPLETE = '2' 390338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_UPDATE_COMPLETE = '3' 400338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_DOWNLOAD_STARTED = '13' 410338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_TYPE_DOWNLOAD_FINISHED = '14' 42fac9a5d238337da91939328386c2fa4fdfb6d957Alex DeymoEVENT_TYPE_REBOOTED_AFTER_UPDATE = '54' 430338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 440338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold# Update event results. 450338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_ERROR = '0' 460338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_SUCCESS = '1' 470338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_SUCCESS_REBOOT = '2' 480338ff3b754d52b41ca2d0432164a757daa1112dGilad ArnoldEVENT_RESULT_UPDATE_DEFERRED = '9' 490338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 50a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold# Omaha event types/results, from update_engine/omaha_request_action.h 51a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold# These are stored in dict form in order to easily print out the keys. 52a0ca5707ed10a6575ed290f341294331455f7769Gilad ArnoldEVENT_TYPE_DICT = { 53a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_TYPE_DOWNLOAD_COMPLETE: 'download_complete', 54a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_TYPE_INSTALL_COMPLETE: 'install_complete', 55a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_TYPE_UPDATE_COMPLETE: 'update_complete', 56a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_TYPE_DOWNLOAD_STARTED: 'download_started', 57fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo EVENT_TYPE_DOWNLOAD_FINISHED: 'download_finished', 58fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo EVENT_TYPE_REBOOTED_AFTER_UPDATE: 'rebooted_after_update' 59a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold} 60a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 61a0ca5707ed10a6575ed290f341294331455f7769Gilad ArnoldEVENT_RESULT_DICT = { 62a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_RESULT_ERROR: 'error', 63a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_RESULT_SUCCESS: 'success', 64a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_RESULT_SUCCESS_REBOOT: 'success_reboot', 65a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold EVENT_RESULT_UPDATE_DEFERRED: 'update_deferred' 66a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold} 67a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 680338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 69a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddockclass ExpectedUpdateEventChainFailed(error.TestFail): 70a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock """Raised if we fail to receive an expected event in a chain.""" 71fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 72fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 730ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass ExpectedUpdateEvent(object): 74248108c1c925791d926105f42212b1033213a4dcGilad Arnold """Defines an expected event in an update process.""" 7545f02ae47134953169805d281992c9edf0019250Chris Sosa 760338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold _ATTR_NAME_DICT_MAP = { 77a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'event_type': EVENT_TYPE_DICT, 78a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'event_result': EVENT_RESULT_DICT, 790338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold } 800338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 81a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold _VALID_TYPES = set(EVENT_TYPE_DICT.keys()) 82a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold _VALID_RESULTS = set(EVENT_RESULT_DICT.keys()) 8345f02ae47134953169805d281992c9edf0019250Chris Sosa 840ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __init__(self, event_type=None, event_result=None, version=None, 85248108c1c925791d926105f42212b1033213a4dcGilad Arnold previous_version=None, on_error=None): 86248108c1c925791d926105f42212b1033213a4dcGilad Arnold """Initializes an event expectation. 87248108c1c925791d926105f42212b1033213a4dcGilad Arnold 88248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param event_type: Expected event type. 89248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param event_result: Expected event result code. 90248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param version: Expected reported image version. 91248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param previous_version: Expected reported previous image version. 92248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param on_error: This is either an object to be returned when a received 93248108c1c925791d926105f42212b1033213a4dcGilad Arnold event mismatches the expectation, or a callable used 94248108c1c925791d926105f42212b1033213a4dcGilad Arnold for generating one. In the latter case, takes as 95248108c1c925791d926105f42212b1033213a4dcGilad Arnold input two attribute dictionaries (expected and actual) 96248108c1c925791d926105f42212b1033213a4dcGilad Arnold and an iterable of mismatched keys. If None, a generic 97248108c1c925791d926105f42212b1033213a4dcGilad Arnold message is returned. 98248108c1c925791d926105f42212b1033213a4dcGilad Arnold """ 990338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if event_type and event_type not in self._VALID_TYPES: 10045f02ae47134953169805d281992c9edf0019250Chris Sosa raise ValueError('event_type %s is not valid.' % event_type) 10145f02ae47134953169805d281992c9edf0019250Chris Sosa 1020338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if event_result and event_result not in self._VALID_RESULTS: 10345f02ae47134953169805d281992c9edf0019250Chris Sosa raise ValueError('event_result %s is not valid.' % event_result) 10445f02ae47134953169805d281992c9edf0019250Chris Sosa 1050ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._expected_attrs = { 1060ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'event_type': event_type, 1070ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'event_result': event_result, 1080ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'version': version, 1090ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 'previous_version': previous_version, 1100ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold } 111248108c1c925791d926105f42212b1033213a4dcGilad Arnold self._on_error = on_error 1120ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1130ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1140338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold @staticmethod 1150338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold def _attr_val_str(attr_val, helper_dict, default=None): 1160338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """Returns an enriched attribute value string, or default.""" 1170338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if not attr_val: 1180338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return default 1190338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1200338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold s = str(attr_val) 1210338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold if helper_dict: 1220338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold s += ':%s' % helper_dict.get(attr_val, 'unknown') 1230338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1240338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return s 1250338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1260338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1270338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold def _attr_name_and_values(self, attr_name, expected_attr_val, 1280338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual_attr_val=None): 1290338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """Returns an attribute name, expected and actual value strings. 1300338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1310338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold This will return (name, expected, actual); the returned value for 1320338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual will be None if its respective input is None/empty. 1330338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1340338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold """ 1350338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold helper_dict = self._ATTR_NAME_DICT_MAP.get(attr_name) 1360338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold expected_attr_val_str = self._attr_val_str(expected_attr_val, 1370338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold helper_dict, 1380338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold default='any') 1390338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold actual_attr_val_str = self._attr_val_str(actual_attr_val, helper_dict) 1400338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1410338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return attr_name, expected_attr_val_str, actual_attr_val_str 1420338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1430338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 144248108c1c925791d926105f42212b1033213a4dcGilad Arnold def _attrs_to_str(self, attrs_dict): 1450338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold return ' '.join(['%s=%s' % 1460338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold self._attr_name_and_values(attr_name, attr_val)[0:2] 147248108c1c925791d926105f42212b1033213a4dcGilad Arnold for attr_name, attr_val in attrs_dict.iteritems()]) 148248108c1c925791d926105f42212b1033213a4dcGilad Arnold 149248108c1c925791d926105f42212b1033213a4dcGilad Arnold 150248108c1c925791d926105f42212b1033213a4dcGilad Arnold def __str__(self): 151248108c1c925791d926105f42212b1033213a4dcGilad Arnold return self._attrs_to_str(self._expected_attrs) 1520ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1530ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1540ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def verify(self, actual_event): 1550ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verify the attributes of an actual event. 1560ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 157ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa @param actual_event: a dictionary containing event attributes 1580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 159248108c1c925791d926105f42212b1033213a4dcGilad Arnold @return An error message, or None if all attributes as expected. 1600ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1610ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 162248108c1c925791d926105f42212b1033213a4dcGilad Arnold mismatched_attrs = [ 163a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock attr_name for attr_name, expected_attr_val 164a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock in self._expected_attrs.iteritems() 165a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock if (expected_attr_val and 166a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock not self._verify_attr(attr_name, expected_attr_val, 167a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock actual_event.get(attr_name)))] 168248108c1c925791d926105f42212b1033213a4dcGilad Arnold if not mismatched_attrs: 169248108c1c925791d926105f42212b1033213a4dcGilad Arnold return None 170248108c1c925791d926105f42212b1033213a4dcGilad Arnold if callable(self._on_error): 171248108c1c925791d926105f42212b1033213a4dcGilad Arnold return self._on_error(self._expected_attrs, actual_event, 172248108c1c925791d926105f42212b1033213a4dcGilad Arnold mismatched_attrs) 173248108c1c925791d926105f42212b1033213a4dcGilad Arnold if self._on_error is None: 174248108c1c925791d926105f42212b1033213a4dcGilad Arnold return ('Received event (%s) does not match expectation (%s)' % 175248108c1c925791d926105f42212b1033213a4dcGilad Arnold (self._attrs_to_str(actual_event), self)) 176248108c1c925791d926105f42212b1033213a4dcGilad Arnold return self._on_error 1770ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1780ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1790ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def _verify_attr(self, attr_name, expected_attr_val, actual_attr_val): 1800ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies that an actual log event attributes matches expected on. 1810ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1820ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param attr_name: name of the attribute to verify 1830ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param expected_attr_val: expected attribute value 1840ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param actual_attr_val: actual attribute value 1850ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1860ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return True if actual value is present and matches, False otherwise. 1870ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1880ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 18945f02ae47134953169805d281992c9edf0019250Chris Sosa # None values are assumed to be missing and non-matching. 190f014ab424450fd595c347d905ac06ccf3d6faaddGilad Arnold if actual_attr_val is None: 1910338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.error('No value found for %s (expected %s)', 1920338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold *self._attr_name_and_values(attr_name, 1930338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold expected_attr_val)[0:2]) 19445f02ae47134953169805d281992c9edf0019250Chris Sosa return False 19545f02ae47134953169805d281992c9edf0019250Chris Sosa 19616e76893c34739649a751f42b3881b57620d665cGilad Arnold # We allow expected version numbers (e.g. 2940.0.0) to be contained in 19716e76893c34739649a751f42b3881b57620d665cGilad Arnold # actual values (2940.0.0-a1); this is necessary for the test to pass 19816e76893c34739649a751f42b3881b57620d665cGilad Arnold # with developer / non-release images. 19916e76893c34739649a751f42b3881b57620d665cGilad Arnold if (actual_attr_val == expected_attr_val or 20016e76893c34739649a751f42b3881b57620d665cGilad Arnold ('version' in attr_name and expected_attr_val in actual_attr_val)): 20116e76893c34739649a751f42b3881b57620d665cGilad Arnold return True 2020ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 20316e76893c34739649a751f42b3881b57620d665cGilad Arnold return False 2040ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2050ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 206248108c1c925791d926105f42212b1033213a4dcGilad Arnold def get_attrs(self): 207248108c1c925791d926105f42212b1033213a4dcGilad Arnold """Returns a dictionary of expected attributes.""" 208248108c1c925791d926105f42212b1033213a4dcGilad Arnold return dict(self._expected_attrs) 209248108c1c925791d926105f42212b1033213a4dcGilad Arnold 2103f9543109fc26571607da554e285eaf069ab2d51David Haddock 2110ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass ExpectedUpdateEventChain(object): 2120ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Defines a chain of expected update events.""" 213248108c1c925791d926105f42212b1033213a4dcGilad Arnold def __init__(self): 214fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo self._expected_events_chain = [] 2153f9543109fc26571607da554e285eaf069ab2d51David Haddock self._current_timestamp = None 2160ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2170ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 218fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo def add_event(self, expected_events, timeout, on_timeout=None): 219248108c1c925791d926105f42212b1033213a4dcGilad Arnold """Adds an expected event to the chain. 220248108c1c925791d926105f42212b1033213a4dcGilad Arnold 221fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo @param expected_events: The ExpectedEvent, or a list thereof, to wait 222fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo for. If a list is passed, it will wait for *any* 223fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo of the provided events, but only one of those. 224248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param timeout: A timeout (in seconds) to wait for the event. 225248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param on_timeout: An error string to use if the event times out. If 226248108c1c925791d926105f42212b1033213a4dcGilad Arnold None, a generic message is used. 2270ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 228fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo if isinstance(expected_events, ExpectedUpdateEvent): 22916e76893c34739649a751f42b3881b57620d665cGilad Arnold expected_events = [expected_events] 230fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo self._expected_events_chain.append( 231fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo (expected_events, timeout, on_timeout)) 2320ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2330ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 234cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold @staticmethod 235fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo def _format_event_with_timeout(expected_events, timeout): 236cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """Returns a string representation of the event, with timeout.""" 237248108c1c925791d926105f42212b1033213a4dcGilad Arnold until = 'within %s seconds' % timeout if timeout else 'indefinitely' 238fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo return '%s, %s' % (' OR '.join(map(str, expected_events)), until) 2390ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2400ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2410ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __str__(self): 2420ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return ('[%s]' % 2430ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold ', '.join( 244fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo [self._format_event_with_timeout(expected_events, timeout) 245fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo for expected_events, timeout, _ 246fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo in self._expected_events_chain])) 2470ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2480ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2490ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def __repr__(self): 250fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo return str(self._expected_events_chain) 2510ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2520ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2530ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def verify(self, get_next_event): 2540ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies that an actual stream of events complies. 2550ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2560ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param get_next_event: a function returning the next event 2570ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 258ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify an event. 2590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2600ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 261fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo for expected_events, timeout, on_timeout in self._expected_events_chain: 2620338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Expecting %s', 263fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo self._format_event_with_timeout(expected_events, 264248108c1c925791d926105f42212b1033213a4dcGilad Arnold timeout)) 265248108c1c925791d926105f42212b1033213a4dcGilad Arnold err_msg = self._verify_event_with_timeout( 266fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo expected_events, timeout, on_timeout, get_next_event) 267248108c1c925791d926105f42212b1033213a4dcGilad Arnold if err_msg is not None: 268248108c1c925791d926105f42212b1033213a4dcGilad Arnold logging.error('Failed expected event: %s', err_msg) 269248108c1c925791d926105f42212b1033213a4dcGilad Arnold raise ExpectedUpdateEventChainFailed(err_msg) 2700ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2710ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2723f9543109fc26571607da554e285eaf069ab2d51David Haddock def _verify_event_with_timeout(self, expected_events, timeout, on_timeout, 273248108c1c925791d926105f42212b1033213a4dcGilad Arnold get_next_event): 2740ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verify an expected event occurs within a given timeout. 2750ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 276fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo @param expected_events: the list of possible events expected next 277248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param timeout: specified in seconds 278248108c1c925791d926105f42212b1033213a4dcGilad Arnold @param on_timeout: A string to return if timeout occurs, or None. 2790ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @param get_next_event: function returning the next event in a stream 2800ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 281248108c1c925791d926105f42212b1033213a4dcGilad Arnold @return None if event complies, an error string otherwise. 2820ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 2830ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 2843f9543109fc26571607da554e285eaf069ab2d51David Haddock new_event = get_next_event() 2853f9543109fc26571607da554e285eaf069ab2d51David Haddock if new_event: 2863f9543109fc26571607da554e285eaf069ab2d51David Haddock # If this is the first event, set it as the current time 2873f9543109fc26571607da554e285eaf069ab2d51David Haddock if self._current_timestamp is None: 2883f9543109fc26571607da554e285eaf069ab2d51David Haddock self._current_timestamp = datetime.strptime(new_event[ 2893f9543109fc26571607da554e285eaf069ab2d51David Haddock 'timestamp'], 2903f9543109fc26571607da554e285eaf069ab2d51David Haddock '%Y-%m-%d %H:%M:%S') 2913f9543109fc26571607da554e285eaf069ab2d51David Haddock 2923f9543109fc26571607da554e285eaf069ab2d51David Haddock # Get the time stamp for the current event and convert to datetime 2933f9543109fc26571607da554e285eaf069ab2d51David Haddock timestamp = new_event['timestamp'] 2943f9543109fc26571607da554e285eaf069ab2d51David Haddock event_timestamp = datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S') 2953f9543109fc26571607da554e285eaf069ab2d51David Haddock 2963f9543109fc26571607da554e285eaf069ab2d51David Haddock # Add the timeout onto the timestamp to get its expiry 2973f9543109fc26571607da554e285eaf069ab2d51David Haddock event_timeout = self._current_timestamp + timedelta(seconds=timeout) 2983f9543109fc26571607da554e285eaf069ab2d51David Haddock 2993f9543109fc26571607da554e285eaf069ab2d51David Haddock # If the event happened before the timeout 3003f9543109fc26571607da554e285eaf069ab2d51David Haddock if event_timestamp < event_timeout: 3013f9543109fc26571607da554e285eaf069ab2d51David Haddock difference = event_timestamp - self._current_timestamp 3023f9543109fc26571607da554e285eaf069ab2d51David Haddock logging.info('Event took %s seconds to fire during the ' 3033f9543109fc26571607da554e285eaf069ab2d51David Haddock 'update', difference.seconds) 30416e76893c34739649a751f42b3881b57620d665cGilad Arnold results = [event.verify(new_event) for event in expected_events] 3053f9543109fc26571607da554e285eaf069ab2d51David Haddock self._current_timestamp = event_timestamp 30616e76893c34739649a751f42b3881b57620d665cGilad Arnold return None if None in results else ' AND '.join(results) 3070ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3080338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.error('Timeout expired') 309248108c1c925791d926105f42212b1033213a4dcGilad Arnold if on_timeout is None: 310248108c1c925791d926105f42212b1033213a4dcGilad Arnold return ('Waiting for event %s timed out after %d seconds' % 311fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo (' OR '.join(map(str, expected_events)), timeout)) 312248108c1c925791d926105f42212b1033213a4dcGilad Arnold return on_timeout 3130ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3140ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3150ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnoldclass UpdateEventLogVerifier(object): 3160ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Verifies update event chains on a devserver update log.""" 317a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock def __init__(self, event_log_filename): 318a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock self._event_log_filename = event_log_filename 3190ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._event_log = [] 3200ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._num_consumed_events = 0 3210ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3220ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 323fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo def verify_expected_events_chain(self, expected_event_chain): 324ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa """Verify a given event chain. 325ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa 326ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa @param expected_event_chain: instance of expected event chain. 327ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 328ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify the an 329ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa event. 330ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa """ 331ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa expected_event_chain.verify(self._get_next_log_event) 3320ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3330ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3340ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold def _get_next_log_event(self): 3350ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """Returns the next event in an event log. 3360ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 337a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock Uses the filename handed to it during initialization to read the 338a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock host log from devserver used during the update. 3390ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3400ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return The next new event in the host log, as reported by devserver; 34103901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold None if no such event was found or an error occurred. 3420ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3430ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 344a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock # (Re)read event log from hostlog file, if necessary. 3450ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if len(self._event_log) <= self._num_consumed_events: 34603901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold try: 347a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock with open(self._event_log_filename, 'r') as out_log: 348a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock self._event_log = json.loads(out_log.read()) 349a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock except Exception as e: 350a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock raise error.TestFail('Error while reading the hostlogs ' 351ab2884bab13c08f21aaa780a1861959131a6f682David Haddock 'from devserver: %s' % e) 3520ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 35303901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold # Return next new event, if one is found. 3540ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold if len(self._event_log) > self._num_consumed_events: 3557572b05fd3356b2ddf6866958e80c7885e44647bGilad Arnold new_event = { 3567572b05fd3356b2ddf6866958e80c7885e44647bGilad Arnold key: str(val) for key, val 3577572b05fd3356b2ddf6866958e80c7885e44647bGilad Arnold in self._event_log[self._num_consumed_events].iteritems() 3587572b05fd3356b2ddf6866958e80c7885e44647bGilad Arnold } 3590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold self._num_consumed_events += 1 3600338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Consumed new event: %s', new_event) 3610ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold return new_event 3620ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 3630ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 364f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnoldclass TestPlatform(object): 365f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """An interface and factory for platform-dependent functionality.""" 36615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 3672f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # Named tuple containing urls for staged urls needed for test. 3682f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # source_url: url to find the update payload for the source image. 3692f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # source_stateful_url: url to find the stateful payload for the source 3702f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # image. 3712f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # target_url: url to find the update payload for the target image. 3722f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # target_stateful_url: url to find the stateful payload for the target 3732f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa # image. 374f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold StagedURLs = collections.namedtuple( 375f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 'StagedURLs', 3762f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa ['source_url', 'source_stateful_url', 'target_url', 3772f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 'target_stateful_url']) 3782f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 3790ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 380f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def __init__(self): 381f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold assert False, 'Cannot instantiate this interface' 382f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 383f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 384f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @staticmethod 385f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def create(host): 386f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Returns a TestPlatform implementation based on the host type. 387f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 388f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold *DO NOT* override this method. 389f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 390f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param host: a host object representing the DUT 391f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 392f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return A TestPlatform implementation. 393f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 394f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold os_type = host.get_os_type() 395585cbd6a5cc32db99c6745aa4333471b6b095b43Keith Haddow if os_type in ('cros', 'moblab'): 396f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return ChromiumOSTestPlatform(host) 397f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 398f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise error.TestError('Unknown OS type reported by host: %s' % os_type) 399f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 4000ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 401a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock def initialize(self, autotest_devserver): 402f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Initialize the object. 4030ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 404f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param autotest_devserver: Instance of client.common_lib.dev_server to 405f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold use to reach the devserver instance for this 406f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold build. 4070ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 408f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 4090ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 4100ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 411f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def prep_artifacts(self, test_conf): 412f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Prepares update artifacts for the test. 41309706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 414f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold The test config must include 'source_payload_uri' and 415f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 'target_payload_uri'. In addition, it may include platform-specific 416f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold values as determined by the test control file. 41709706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 418f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param test_conf: Dictionary containing the test configuration. 41909706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 420f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return A tuple of staged URLs. 421f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 422f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @raise error.TestError on failure. 42309706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold """ 424f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 42509706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 42609706f18ea3878f1b173a63fdc92f2fc6450bb4dGilad Arnold 427f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def reboot_device(self): 428f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Reboots the device.""" 429f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 430f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 431f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 432a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock def prep_device_for_update(self, source_payload_uri): 433f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Prepares the device for update. 434f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 435a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock @param source_payload_uri: Source payload GS URI to install. 436f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 437f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @raise error.TestError on failure. 438f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 439f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 440f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 441f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 442f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def get_active_slot(self): 443f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Returns the active boot slot of the device.""" 444f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 445f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 446f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 447f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def start_update_perf(self, bindir): 448f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Starts performance monitoring (if available). 449f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 450f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param bindir: Directory containing test binary files. 451f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 452f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 453f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 454f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 455aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock def stop_update_perf(self, resultdir): 456f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Stops performance monitoring and returns data (if available). 457f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 458aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock @param resultdir: Directory containing test result files. 459f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return Dictionary containing performance attributes. 460f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 461f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 462f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 463f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 464a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock def trigger_update(self, target_payload_uri): 465f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Kicks off an update. 466f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 467a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock @param target_payload_uri: The GS URI to use for the update. 468f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 469f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 470f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 471f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 472f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def finalize_update(self): 473f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Performs post-update procedures.""" 474f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 475f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 476f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 477f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def get_update_log(self, num_lines): 478f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Returns the update log. 479f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 480f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param num_lines: Number of log lines to return (tail), zero for all. 481f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 482f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return String containing the last |num_lines| from the update log. 483f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 484f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 485f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 486f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 487a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock def check_device_after_update(self): 488f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Runs final sanity checks. 489f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 490f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @raise error.TestError on failure. 491f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 492f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold raise NotImplementedError 493f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 494f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 49534618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar def oobe_triggers_update(self): 49634618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar """Returns True if this host has an OOBE flow during which 49734618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar it will perform an update check and perhaps an update. 49834618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar One example of such a flow is Hands-Off Zero-Touch Enrollment. 49934618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar 50034618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar @return Boolean indicating whether the DUT's OOBE triggers an update. 50134618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar """ 50234618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar raise NotImplementedError 50334618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar 50434618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar 50534618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar def verify_version(self, version): 50634618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar """Compares the OS version on the DUT with the provided version. 50734618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar 50834618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar @param version: The version to compare with (string). 50934618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar @raise error.TestFail if the versions differ. 51034618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar """ 51134618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar actual_version = self._host.get_release_version() 51234618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar if actual_version != version: 51334618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar err_msg = 'Failed to verify OS version. Expected %s, was %s' % ( 51434618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar version, actual_version) 51534618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar logging.error(err_msg) 51634618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar raise error.TestFail(err_msg) 51734618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar 51834618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar 519f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnoldclass ChromiumOSTestPlatform(TestPlatform): 520f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """A TestPlatform implementation for Chromium OS.""" 521f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 522f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _STATEFUL_UPDATE_FILENAME = 'stateful.tgz' 523f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 524f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def __init__(self, host): 525f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._host = host 526f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._autotest_devserver = None 527f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._staged_urls = None 528f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._perf_mon_pid = None 529f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 530f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 531a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock def _stage_payload(self, build_name, filename, archive_url=None): 5322f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Stage the given payload onto the devserver. 5330ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 5342f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa Works for either a stateful or full/delta test payload. Expects the 535a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock gs_path or a combo of build_name + filename. 536a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 537a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock @param build_name: The build name e.g. x86-mario-release/<version>. 538a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock If set, assumes default gs archive bucket and 539a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock requires filename to be specified. 540a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock @param filename: In conjunction with build_name, this is the file you 541a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock are downloading. 54215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @param archive_url: An optional GS archive location, if not using the 54315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold devserver's default. 544ae6acd9b3e1c6f56310cdb4e05737122b7b2818cChris Sosa 5450ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @return URL of the staged payload on the server. 5460ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 5470ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold @raise error.TestError if there's a problem with staging. 5480ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 5490ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 5502f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa try: 551a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock self._autotest_devserver.stage_artifacts(image=build_name, 552a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock files=[filename], 553a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock archive_url=archive_url) 554f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return self._autotest_devserver.get_staged_file_url(filename, 555a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock build_name) 5562f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa except dev_server.DevServerException, e: 5570338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold raise error.TestError('Failed to stage payload: %s' % e) 5580ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 5590ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 560f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _stage_payload_by_uri(self, payload_uri): 56115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """Stage a payload based on its GS URI. 56215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 56315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold This infers the build's label, filename and GS archive from the 56415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold provided GS URI. 56515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 56615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @param payload_uri: The full GS URI of the payload. 56715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 56815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @return URL of the staged payload on the server. 56915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 57015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold @raise error.TestError if there's a problem with staging. 57115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 57215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """ 57315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold archive_url, _, filename = payload_uri.rpartition('/') 574a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock build_name = urlparse.urlsplit(archive_url).path.strip('/') 575a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock return self._stage_payload(build_name, filename, 57694694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold archive_url=archive_url) 57715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 57815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 57915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold def _get_stateful_uri(self, build_uri): 58015384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """Returns a complete GS URI of a stateful update given a build path.""" 58115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold return '/'.join([build_uri.rstrip('/'), self._STATEFUL_UPDATE_FILENAME]) 58215384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 58315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 58415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold def _payload_to_stateful_uri(self, payload_uri): 58515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold """Given a payload GS URI, returns the corresponding stateful URI.""" 58615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold build_uri = payload_uri.rpartition('/')[0] 587d8b9093f06cb882f7f46ca2f51d06630c9004f6dGwendal Grignou if build_uri.endswith('payloads'): 588d8b9093f06cb882f7f46ca2f51d06630c9004f6dGwendal Grignou build_uri = build_uri.rpartition('/')[0] 58915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold return self._get_stateful_uri(build_uri) 5902f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 5912f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 592a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock @staticmethod 593a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock def _get_update_parameters_from_uri(payload_uri): 594a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock """Extract the two vars needed for cros_au from the Google Storage URI. 595cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 596a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock dev_server.auto_update needs two values from this test: 597a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock (1) A build_name string e.g samus-release/R60-9583.0.0 598a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock (2) A filename of the exact payload file to use for the update. This 599a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock payload needs to have already been staged on the devserver. 600cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold 601a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock This function extracts those two values from a Google Storage URI. 602a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 603a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock @param payload_uri: Google Storage URI to extract values from 604cfa14a695654bc9cbfe9b9ce5868d669d0c57e0fGilad Arnold """ 605a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock archive_url, _, payload_file = payload_uri.rpartition('/') 606a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock build_name = urlparse.urlsplit(archive_url).path.strip('/') 607a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 608a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock # This test supports payload uris from two Google Storage buckets. 609a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock # They store their payloads slightly differently. One stores them in 610a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock # a separate payloads directory. E.g 611a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock # gs://chromeos-image-archive/samus-release/R60-9583.0.0/blah.bin 612a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock # gs://chromeos-releases/dev-channel/samus/9334.0.0/payloads/blah.bin 613a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock if build_name.endswith('payloads'): 614a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock build_name = build_name.rpartition('/')[0] 615a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock payload_file = 'payloads/' + payload_file 616a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 617a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock logging.debug('Extracted build_name: %s, payload_file: %s from %s.', 618a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock build_name, payload_file, payload_uri) 619a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock return build_name, payload_file 620a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 621a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 6220c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou def _install_version(self, payload_uri, clobber_stateful=False): 6230c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou """Install the specified host with the image given by the url. 624a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 625a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock @param payload_uri: GS URI used to compute values for devserver cros_au 6260c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou @param clobber_stateful: force a reinstall of the stateful image. 6272f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """ 62803286f0f93ff59fc1744099378201f85db9c1883Gwendal Grignou 629a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock build_name, payload_file = self._get_update_parameters_from_uri( 630a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock payload_uri) 6310c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou logging.info('Installing image %s on the DUT', payload_uri) 632a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 633a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock try: 6340c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou ds = self._autotest_devserver 6350c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou _, pid = ds.auto_update(host_name=self._host.hostname, 6360c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou build_name=build_name, 6370c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou force_update=True, 6380c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou full_update=True, 6390c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou log_dir=self._results_dir, 6400c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou payload_filename=payload_file, 6410c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou clobber_stateful=clobber_stateful) 642a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock except: 6430c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou logging.fatal('ERROR: Failed to install image on the DUT.') 644a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock raise 6450c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou return pid 646f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 647f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 648f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _stage_artifacts_onto_devserver(self, test_conf): 6492f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa """Stages artifacts that will be used by the test onto the devserver. 6502f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 6512f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa @param test_conf: a dictionary containing test configuration values 6522f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 653f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @return a StagedURLs tuple containing the staged urls. 654f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa """ 6550338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Staging images onto autotest devserver (%s)', 656f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._autotest_devserver.url()) 657f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 65815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_source_url = None 659a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock source_payload_uri = test_conf['source_payload_uri'] 660a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 6614cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold if source_payload_uri: 66294694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold staged_source_url = self._stage_payload_by_uri(source_payload_uri) 6634cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold 6644cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # In order to properly install the source image using a full 6654cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # payload we'll also need the stateful update that comes with it. 6664cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # In general, tests may have their source artifacts in a different 6674cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # location than their payloads. This is determined by whether or 6684cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # not the source_archive_uri attribute is set; if it isn't set, 6694cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # then we derive it from the dirname of the source payload. 6704cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_archive_uri = test_conf.get('source_archive_uri') 6714cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold if source_archive_uri: 6724cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_stateful_uri = self._get_stateful_uri(source_archive_uri) 6732f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa else: 6744cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_stateful_uri = self._payload_to_stateful_uri( 6754cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_payload_uri) 676fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold 6774cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold staged_source_stateful_url = self._stage_payload_by_uri( 67894694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold source_stateful_uri) 67915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 6804cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold # Log source image URLs. 6814cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold logging.info('Source full payload from %s staged at %s', 6824cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_payload_uri, staged_source_url) 6834cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold if staged_source_stateful_url: 6844cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold logging.info('Source stateful update from %s staged at %s', 6854cec366fff66e4603d9851c76680a6bb3f10fbe6Gilad Arnold source_stateful_uri, staged_source_stateful_url) 68615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 68715384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_payload_uri = test_conf['target_payload_uri'] 68894694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold staged_target_url = self._stage_payload_by_uri(target_payload_uri) 68915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_stateful_uri = None 6900e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold staged_target_stateful_url = None 69115384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_archive_uri = test_conf.get('target_archive_uri') 6920e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold if target_archive_uri: 6930e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold target_stateful_uri = self._get_stateful_uri(target_archive_uri) 6942f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa else: 6957b8e9b580b9883fc60bee7d26973c6d8d14cb5c8David Haddock target_stateful_uri = self._payload_to_stateful_uri( 69615384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold target_payload_uri) 697f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 6980e18ad5f71d48432747733e10aad1e1cf5d93113Gilad Arnold if not staged_target_stateful_url and target_stateful_uri: 69915384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_stateful_url = self._stage_payload_by_uri( 70094694ec92c9e2c4d316aed34453ef75c21444c61Gilad Arnold target_stateful_uri) 7012f1ae9f1f2464ebbeb226a6669fa90ef211a179cChris Sosa 702fea7e766e59f8356dad6f70e46c0ee25997863a5Gilad Arnold # Log target payload URLs. 70315384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold logging.info('%s test payload from %s staged at %s', 70415384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold test_conf['update_type'], target_payload_uri, 70515384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold staged_target_url) 7060338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Target stateful update from %s staged at %s', 7077b8e9b580b9883fc60bee7d26973c6d8d14cb5c8David Haddock target_stateful_uri, staged_target_stateful_url) 70815384a4ded97f171906a72106791d19e96e68fa7Gilad Arnold 709f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return self.StagedURLs(staged_source_url, staged_source_stateful_url, 710f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold staged_target_url, staged_target_stateful_url) 711f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 712f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 713a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock def _run_login_test(self, tag): 7141192c41145b533f4138434bfa7e6ba2af9f75330David Haddock """Runs login_LoginSuccess test on the DUT.""" 715a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock client_at = autotest.Autotest(self._host) 716a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock client_at.run_test('login_LoginSuccess', tag=tag) 717c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 718c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 719f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Interface overrides. 720f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # 721a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock def initialize(self, autotest_devserver, results_dir): 722f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._autotest_devserver = autotest_devserver 723a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock self._results_dir = results_dir 724f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 725f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 726f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def reboot_device(self): 727f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._host.reboot() 728f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 729f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 730f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def prep_artifacts(self, test_conf): 731f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._staged_urls = self._stage_artifacts_onto_devserver(test_conf) 732f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return self._staged_urls 733f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 734f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 735a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock def prep_device_for_update(self, source_payload_uri): 736f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Install the source version onto the DUT. 737f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if self._staged_urls.source_url: 7380c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou self._install_version(source_payload_uri, clobber_stateful=True) 739f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 740a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock # Make sure we can login before the target update. 741a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock self._run_login_test('source_update') 742f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 743f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 744f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def get_active_slot(self): 745f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return self._host.run('rootdev -s').stdout.strip() 746f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 747f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 748f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def start_update_perf(self, bindir): 749aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock """Copy performance monitoring script to DUT. 750f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 751aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock The updater will kick off the script during the update. 752aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock """ 753aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock path = os.path.join(bindir, UPDATE_ENGINE_PERF_SCRIPT) 754aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock self._host.send_file(path, UPDATE_ENGINE_PERF_PATH) 755f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 756f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 757aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock def stop_update_perf(self, resultdir): 758aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock """ Copy the performance metrics back from the DUT.""" 759aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock try: 760aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock path = os.path.join('/var/log', UPDATE_ENGINE_PERF_RESULTS_FILE) 761aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock self._host.get_file(path, resultdir) 762aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock self._host.run('rm %s' % path) 763aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock script = os.path.join(UPDATE_ENGINE_PERF_PATH, 764aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock UPDATE_ENGINE_PERF_SCRIPT) 765aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock self._host.run('rm %s' % script) 766aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock return os.path.join(resultdir, UPDATE_ENGINE_PERF_RESULTS_FILE) 767aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock except: 768aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock logging.debug('Failed to copy performance metrics from DUT.') 769aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock return None 770f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 771f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 772a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock def trigger_update(self, target_payload_uri): 773a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock logging.info('Updating device to target image.') 7740c13495f06d389adeabbb95f858c9b0c836d2492Gwendal Grignou return self._install_version(target_payload_uri) 775f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 776f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def finalize_update(self): 777a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock # Stateful update is controlled by cros_au 778a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock pass 779f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 780f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 781f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def get_update_log(self, num_lines): 782f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold return self._host.run_output( 783fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold 'tail -n %d /var/log/update_engine.log' % num_lines, 784fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold stdout_tee=None) 785f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 786f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 787a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock def check_device_after_update(self): 788f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Make sure we can login after update. 789a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock self._run_login_test('target_update') 790f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 791f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 79234618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar def oobe_triggers_update(self): 79334618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar return self._host.oobe_triggers_update() 79434618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar 79534618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar 796f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnoldclass autoupdate_EndToEndTest(test.test): 797f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Complete update test between two Chrome OS releases. 798f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 799f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold Performs an end-to-end test of updating a ChromeOS device from one version 800f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold to another. The test performs the following steps: 801f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 802f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1. Stages the source (full) and target update payload on the central 803f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver. 804a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 2. Installs a source image on the DUT (if provided) and reboots to it. 805a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 3. Then starts the target update by calling cros_au RPC on the devserver. 806a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 4. This copies the devserver code and all payloads to the DUT. 807a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 5. Starts a devserver on the DUT. 808a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 6. Starts an update pointing to this local devserver. 809a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 7. Watches as the DUT applies the update to rootfs and stateful. 810a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 8. Reboots and repeats steps 5-6, ensuring that the next update check 811f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold shows the new image version. 812a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 9. Returns the hostlogs collected during each update check for 813a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock verification against expected update events. 814f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 815f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold Some notes on naming: 816f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold devserver: Refers to a machine running the Chrome OS Update Devserver. 817f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold autotest_devserver: An autotest wrapper to interact with a devserver. 818f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold Can be used to stage artifacts to a devserver. While 819f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold this can also be used to update a machine, we do not 820f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold use it for that purpose in this test as we manage 821f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold updates with out own devserver instances (see below). 822f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold *staged_url's: In this case staged refers to the fact that these items 823f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold are available to be downloaded statically from these urls 824f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold e.g. 'localhost:8080/static/my_file.gz'. These are usually 825f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold given after staging an artifact using a autotest_devserver 826f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold though they can be re-created given enough assumptions. 827f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """ 828f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold version = 1 829f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 830f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Timeout periods, given in seconds. 831f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_INITIAL_UPDATE_CHECK_SECONDS = 12 * 60 832f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # TODO(sosa): Investigate why this needs to be so long (this used to be 833f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # 120 and regressed). 834f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_DOWNLOAD_STARTED_SECONDS = 4 * 60 835f3c5dcd63105ae2f98a9dbb4da1cdbeacd49e832Grant Grundler # See https://crbug.com/731214 before changing WAIT_FOR_DOWNLOAD 836f3c5dcd63105ae2f98a9dbb4da1cdbeacd49e832Grant Grundler _WAIT_FOR_DOWNLOAD_COMPLETED_SECONDS = 20 * 60 837f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_UPDATE_COMPLETED_SECONDS = 4 * 60 838f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold _WAIT_FOR_UPDATE_CHECK_AFTER_REBOOT_SECONDS = 15 * 60 839f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 840a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold # Logs and their whereabouts. 841a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold _WHERE_UPDATE_LOG = ('update_engine log (in sysinfo or on the DUT, also ' 842a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'included in the test log)') 843a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold _WHERE_OMAHA_LOG = 'Omaha-devserver log (included in the test log)' 844a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 845f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 846f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def initialize(self): 847f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Sets up variables that will be used by test.""" 848f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._host = None 849f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._omaha_devserver = None 850a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._source_image_installed = False 851f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 852f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 853f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def cleanup(self): 854f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Kill the omaha devserver if it's still around.""" 855f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if self._omaha_devserver: 856f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._omaha_devserver.stop_devserver() 857f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 858f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._omaha_devserver = None 859f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 860f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 861ab2884bab13c08f21aaa780a1861959131a6f682David Haddock def _get_hostlog_file(self, filename, pid): 862ab2884bab13c08f21aaa780a1861959131a6f682David Haddock """Return the hostlog file location. 863ab2884bab13c08f21aaa780a1861959131a6f682David Haddock 864ab2884bab13c08f21aaa780a1861959131a6f682David Haddock @param filename: The partial filename to look for. 865ab2884bab13c08f21aaa780a1861959131a6f682David Haddock @param pid: The pid of the update. 866ab2884bab13c08f21aaa780a1861959131a6f682David Haddock 867ab2884bab13c08f21aaa780a1861959131a6f682David Haddock """ 868ab2884bab13c08f21aaa780a1861959131a6f682David Haddock hosts = [self._host.hostname, self._host.ip] 869ab2884bab13c08f21aaa780a1861959131a6f682David Haddock for host in hosts: 870ab2884bab13c08f21aaa780a1861959131a6f682David Haddock hostlog = '%s_%s_%s' % (filename, host, pid) 871ab2884bab13c08f21aaa780a1861959131a6f682David Haddock file_url = os.path.join(self.job.resultdir, 872ab2884bab13c08f21aaa780a1861959131a6f682David Haddock dev_server.AUTO_UPDATE_LOG_DIR, 873ab2884bab13c08f21aaa780a1861959131a6f682David Haddock hostlog) 874ab2884bab13c08f21aaa780a1861959131a6f682David Haddock if os.path.exists(file_url): 875ab2884bab13c08f21aaa780a1861959131a6f682David Haddock return file_url 876ab2884bab13c08f21aaa780a1861959131a6f682David Haddock raise error.TestFail('Could not find %s for pid %s' % (filename, pid)) 877ab2884bab13c08f21aaa780a1861959131a6f682David Haddock 878ab2884bab13c08f21aaa780a1861959131a6f682David Haddock 879f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def _dump_update_engine_log(self, test_platform): 880f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold """Dumps relevant AU error log.""" 881f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold try: 882fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold error_log = test_platform.get_update_log(80) 883fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold logging.error('Dumping snippet of update_engine log:\n%s', 884fffb6d7274294d9a57523fb7535dd627d0378e5fGilad Arnold snippet(error_log)) 885f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold except Exception: 886f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Mute any exceptions we get printing debug logs. 887f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold pass 888f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 889f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 890aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock def _report_perf_data(self, perf_file): 89131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """Reports performance and resource data. 89231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 893f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold Currently, performance attributes are expected to include 'rss_peak' 894f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold (peak memory usage in bytes). 895f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 896aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock @param perf_file: A file with performance metrics. 89731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen """ 898aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock logging.debug('Reading perf results from %s.' % perf_file) 899aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock try: 900aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock with open(perf_file, 'r') as perf_file_handle: 901aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock perf_data = json.loads(perf_file_handle.read()) 902aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock except Exception as e: 903aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock logging.warning('Error while reading the perf data file: %s' % e) 904aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock return 905aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock 90631887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen rss_peak = perf_data.get('rss_peak') 90731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen if rss_peak: 90831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen rss_peak_kib = rss_peak / 1024 90931887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen logging.info('Peak memory (RSS) usage on DUT: %d KiB', rss_peak_kib) 91031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen self.output_perf_value(description='mem_usage_peak', 91131887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen value=int(rss_peak_kib), 91231887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen units='KiB', 91331887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen higher_is_better=False) 91431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen else: 915aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock logging.warning('No rss_peak key in JSON returned by %s', 916aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock UPDATE_ENGINE_PERF_SCRIPT) 91731887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 91831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 919a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_initial_check(self, expected, actual, mismatched_attrs): 920a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'version' in mismatched_attrs: 921a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold err_msg = ('Initial update check was received but the reported ' 922a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'version is different from what was expected.') 923a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if self._source_image_installed: 924a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold err_msg += (' The source payload we installed was probably ' 925a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'incorrect or corrupt.') 926a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold else: 927a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold err_msg += (' The DUT is probably not running the correct ' 928a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'source image.') 929a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return err_msg 930a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 931a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return 'A test bug occurred; inspect the test log.' 932a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 933a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 934a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_intermediate(self, expected, actual, mismatched_attrs, action, 935a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold problem): 936a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'event_result' in mismatched_attrs: 9370ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold event_result = actual.get('event_result') 9380ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold reported = (('different than expected (%s)' % 9390ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold EVENT_RESULT_DICT[event_result]) 9400ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold if event_result else 'missing') 9410ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold return ('The updater reported result code is %s. This could be an ' 9420ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'updater bug or a connectivity problem; check the %s. For ' 9430ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'a detailed log of update events, check the %s.' % 9440ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold (reported, self._WHERE_UPDATE_LOG, self._WHERE_OMAHA_LOG)) 945a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'event_type' in mismatched_attrs: 9460ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold event_type = actual.get('event_type') 9470ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold reported = ('different (%s)' % EVENT_TYPE_DICT[event_type] 9480ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold if event_type else 'missing') 9490ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold return ('Expected the updater to %s (%s) but received event type ' 9500ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'is %s. This could be an updater %s; check the ' 951a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold '%s. For a detailed log of update events, check the %s.' % 9520ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold (action, EVENT_TYPE_DICT[expected['event_type']], reported, 9530ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold problem, self._WHERE_UPDATE_LOG, self._WHERE_OMAHA_LOG)) 954a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'version' in mismatched_attrs: 955a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('The updater reported an unexpected version despite ' 956a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'previously reporting the correct one. This is most likely ' 957a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'a bug in update engine; check the %s.' % 958a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WHERE_UPDATE_LOG) 959a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 960a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return 'A test bug occurred; inspect the test log.' 961a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 962a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 963a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_download_started(self, expected, actual, mismatched_attrs): 964a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return self._error_intermediate(expected, actual, mismatched_attrs, 965a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'begin downloading', 966a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'bug, crash or provisioning error') 967a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 968a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 969a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_download_finished(self, expected, actual, mismatched_attrs): 970a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return self._error_intermediate(expected, actual, mismatched_attrs, 971a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'finish downloading', 'bug or crash') 972a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 973a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 974a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _error_update_complete(self, expected, actual, mismatched_attrs): 975a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return self._error_intermediate(expected, actual, mismatched_attrs, 976a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'complete the update', 'bug or crash') 977a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 978a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 97916e76893c34739649a751f42b3881b57620d665cGilad Arnold def _error_reboot_after_update(self, expected, actual, mismatched_attrs): 980a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'event_result' in mismatched_attrs: 9810ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold event_result = actual.get('event_result') 9820ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold reported = ('different (%s)' % EVENT_RESULT_DICT[event_result] 9830ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold if event_result else 'missing') 984a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('The updater was expected to reboot (%s) but reported ' 9850ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'result code is %s. This could be a failure to reboot, an ' 9860ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'updater bug or a connectivity problem; check the %s and ' 9870ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'the system log. For a detailed log of update events, ' 9880ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'check the %s.' % 9890ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold (EVENT_RESULT_DICT[expected['event_result']], reported, 990a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WHERE_UPDATE_LOG, self._WHERE_OMAHA_LOG)) 991a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'event_type' in mismatched_attrs: 9920ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold event_type = actual.get('event_type') 9930ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold reported = ('different (%s)' % EVENT_TYPE_DICT[event_type] 9940ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold if event_type else 'missing') 995a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('Expected to successfully reboot into the new image (%s) ' 9960ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'but received event type is %s. This probably means that ' 9970ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'the new image failed to verify after reboot, possibly ' 9980ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'because the payload is corrupt. This might also be an ' 9990ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'updater bug or crash; check the %s. For a detailed log of ' 10000ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold 'update events, check the %s.' % 10010ba4fcd882643427524c35522bf77959b57c6f48Gilad Arnold (EVENT_TYPE_DICT[expected['event_type']], reported, 1002a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WHERE_UPDATE_LOG, self._WHERE_OMAHA_LOG)) 1003a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'version' in mismatched_attrs: 1004a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('The DUT rebooted after the update but reports a different ' 1005a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'image version than the one expected. This probably means ' 1006a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'that the payload we applied was incorrect or corrupt.') 1007a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if 'previous_version' in mismatched_attrs: 1008a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('The DUT rebooted after the update and reports the ' 1009a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'expected version. However, it reports a previous version ' 1010a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'that is different from the one previously reported. This ' 1011a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'is most likely a bug in update engine; check the %s.' % 1012a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WHERE_UPDATE_LOG) 1013a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1014a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return 'A test bug occurred; inspect the test log.' 1015a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1016a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1017a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold def _timeout_err(self, desc, timeout, event_type=None): 1018a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold if event_type is not None: 1019a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold desc += ' (%s)' % EVENT_TYPE_DICT[event_type] 1020a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold return ('Failed to receive %s within %d seconds. This could be a ' 1021a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'problem with the updater or a connectivity issue. For more ' 1022a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'details, check the %s.' % 1023a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold (desc, timeout, self._WHERE_UPDATE_LOG)) 1024a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1025a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 1026f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold def run_update_test(self, test_platform, test_conf): 1027ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Runs the actual update test once preconditions are met. 10280ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1029f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold @param test_platform: TestPlatform implementation. 1030ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param test_conf: A dictionary containing test configuration values 10310ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1032ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raises ExpectedUpdateEventChainFailed if we failed to verify an update 1033ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa event. 10340ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold """ 1035c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1036f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Record the active root partition. 1037f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold source_active_slot = test_platform.get_active_slot() 1038f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold logging.info('Source active slot: %s', source_active_slot) 10390ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 10407ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold source_release = test_conf['source_release'] 10417ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold target_release = test_conf['target_release'] 10427ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold 1043aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock test_platform.start_update_perf(self.bindir) 104431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen try: 1045a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock # Update the DUT to the target image. 1046a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock pid = test_platform.trigger_update(test_conf['target_payload_uri']) 1047a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 1048a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock # Verify the host log that was returned from the update. 1049ab2884bab13c08f21aaa780a1861959131a6f682David Haddock file_url = self._get_hostlog_file('devserver_hostlog_rootfs', pid) 1050a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 1051a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock logging.info('Checking update steps with devserver hostlog file: ' 1052a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock '%s' % file_url) 1053a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock log_verifier = UpdateEventLogVerifier(file_url) 105431887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 105531887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen # Verify chain of events in a successful update process. 1056248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain = ExpectedUpdateEventChain() 1057248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain.add_event( 1058248108c1c925791d926105f42212b1033213a4dcGilad Arnold ExpectedUpdateEvent( 10597ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold version=source_release, 1060a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_error=self._error_initial_check), 1061a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_INITIAL_UPDATE_CHECK_SECONDS, 1062a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_timeout=self._timeout_err( 1063a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'an initial update check', 1064a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_INITIAL_UPDATE_CHECK_SECONDS)) 1065248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain.add_event( 1066248108c1c925791d926105f42212b1033213a4dcGilad Arnold ExpectedUpdateEvent( 1067248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_type=EVENT_TYPE_DOWNLOAD_STARTED, 1068248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_result=EVENT_RESULT_SUCCESS, 10697ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold version=source_release, 1070a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_error=self._error_download_started), 1071a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_DOWNLOAD_STARTED_SECONDS, 1072a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_timeout=self._timeout_err( 1073a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'a download started notification', 1074a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_DOWNLOAD_STARTED_SECONDS, 1075a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold event_type=EVENT_TYPE_DOWNLOAD_STARTED)) 1076248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain.add_event( 1077248108c1c925791d926105f42212b1033213a4dcGilad Arnold ExpectedUpdateEvent( 1078248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_type=EVENT_TYPE_DOWNLOAD_FINISHED, 1079248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_result=EVENT_RESULT_SUCCESS, 10807ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold version=source_release, 1081a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_error=self._error_download_finished), 1082a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_DOWNLOAD_COMPLETED_SECONDS, 1083a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_timeout=self._timeout_err( 1084a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'a download finished notification', 1085a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_DOWNLOAD_COMPLETED_SECONDS, 1086a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold event_type=EVENT_TYPE_DOWNLOAD_FINISHED)) 1087248108c1c925791d926105f42212b1033213a4dcGilad Arnold chain.add_event( 1088248108c1c925791d926105f42212b1033213a4dcGilad Arnold ExpectedUpdateEvent( 1089248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_type=EVENT_TYPE_UPDATE_COMPLETE, 1090248108c1c925791d926105f42212b1033213a4dcGilad Arnold event_result=EVENT_RESULT_SUCCESS, 10917ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold version=source_release, 1092a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_error=self._error_update_complete), 1093a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_UPDATE_COMPLETED_SECONDS, 1094a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold on_timeout=self._timeout_err( 1095a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold 'an update complete notification', 1096a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._WAIT_FOR_UPDATE_COMPLETED_SECONDS, 1097a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold event_type=EVENT_TYPE_UPDATE_COMPLETE)) 109831887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1099fac9a5d238337da91939328386c2fa4fdfb6d957Alex Deymo log_verifier.verify_expected_events_chain(chain) 110031887b7a4ea7e1517d468c2ccf94df14ba6d0315David Zeuthen 1101a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock except: 1102a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock logging.fatal('ERROR: Failure occurred during the target update.') 1103a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock raise 11040ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1105aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock perf_file = test_platform.stop_update_perf(self.job.resultdir) 1106aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock if perf_file is not None: 1107aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock self._report_perf_data(perf_file) 1108aa97f6e69d7a58bb4e0b20fbd41bcadb42575b9aDavid Haddock 110934618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar if test_platform.oobe_triggers_update(): 111034618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar # If DUT automatically checks for update during OOBE, 111134618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar # checking the post-update CrOS version and slot is sufficient. 111234618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar # This command checks the OS version. 111334618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar # The slot is checked a little later, after the else block. 1114a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock logging.info('Skipping post reboot update check.') 111534618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar test_platform.verify_version(target_release) 111634618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar else: 111734618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar # Observe post-reboot update check, which should indicate that the 111834618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar # image version has been updated. 1119a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock # Verify the host log that was returned from the update. 1120ab2884bab13c08f21aaa780a1861959131a6f682David Haddock file_url = self._get_hostlog_file('devserver_hostlog_reboot', pid) 1121a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 1122a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock logging.info('Checking post-reboot devserver hostlogs: %s' % 1123a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock file_url) 1124a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock log_verifier = UpdateEventLogVerifier(file_url) 1125a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 112634618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar chain = ExpectedUpdateEventChain() 112734618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar expected_events = [ 112834618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar ExpectedUpdateEvent( 112934618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar event_type=EVENT_TYPE_UPDATE_COMPLETE, 113034618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar event_result=EVENT_RESULT_SUCCESS_REBOOT, 113134618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar version=target_release, 113234618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar previous_version=source_release, 113334618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar on_error=self._error_reboot_after_update), 113434618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar # Newer versions send a "rebooted_after_update" message 113534618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar # after reboot with the previous version instead of another 113634618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar # "update_complete". 113734618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar ExpectedUpdateEvent( 113834618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar event_type=EVENT_TYPE_REBOOTED_AFTER_UPDATE, 113934618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar event_result=EVENT_RESULT_SUCCESS, 114034618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar version=target_release, 114134618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar previous_version=source_release, 114234618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar on_error=self._error_reboot_after_update), 114334618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar ] 114434618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar chain.add_event( 114534618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar expected_events, 114634618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar self._WAIT_FOR_UPDATE_CHECK_AFTER_REBOOT_SECONDS, 114734618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar on_timeout=self._timeout_err( 114834618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar 'a successful reboot notification', 114934618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar self._WAIT_FOR_UPDATE_CHECK_AFTER_REBOOT_SECONDS, 115034618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar event_type=EVENT_TYPE_UPDATE_COMPLETE)) 115134618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar 115234618870e735e83db984401a54ca1eecd8e4ac14Niranjan Kumar log_verifier.verify_expected_events_chain(chain) 1153f4fa49b09cfa64e039355f78df2c34a9acca0c0cChris Sosa 1154f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Make sure we're using a different slot after the update. 1155f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold target_active_slot = test_platform.get_active_slot() 1156f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold if target_active_slot == source_active_slot: 11571b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold err_msg = 'The active image slot did not change after the update.' 11587ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold if None in (source_release, target_release): 11597ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold err_msg += (' The DUT likely rebooted into the old image, which ' 11607ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold 'probably means that the payload we applied was ' 11617ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold 'corrupt. But since we did not check the source ' 11627ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold 'and/or target version we cannot say for sure.') 11637ac0a621527b1ecb4b82fea910c730682f9c1f76Gilad Arnold elif source_release == target_release: 11641b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold err_msg += (' Given that the source and target versions are ' 11651b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'identical, the DUT likely rebooted into the old ' 11661b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'image. This probably means that the payload we ' 11671b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'applied was corrupt.') 11681b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold else: 11691b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold err_msg += (' This is strange since the DUT reported the ' 11701b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'correct target version. This is probably a system ' 11711b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold 'bug; check the DUT system log.') 11721b4da911c86c446bef8d0d5cb63dcf605ce6d289Gilad Arnold raise error.TestFail(err_msg) 11730338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold 1174f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold logging.info('Target active slot changed as expected: %s', 1175f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold target_active_slot) 1176eb300ac8af429e51f751b95ce375636fbb649e37Gilad Arnold 11770338ff3b754d52b41ca2d0432164a757daa1112dGilad Arnold logging.info('Update successful, test completed') 11780ed760cbee4ce839988585003d445465bb0b95b9Gilad Arnold 1179ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 11808e00e8b4a421c53a15f751fc90bb06d738ccbd78David Haddock def run_once(self, host, test_conf): 1181ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """Performs a complete auto update test. 1182ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1183ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param host: a host object representing the DUT 1184ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @param test_conf: a dictionary containing test configuration values 1185ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1186ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa @raise error.TestError if anything went wrong with setting up the test; 1187ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa error.TestFail if any part of the test has failed. 1188ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa """ 1189ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa self._host = host 1190a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock logging.debug('The test configuration supplied: %s', test_conf) 1191ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1192009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # Find a devserver to use. We first try to pick a devserver with the 1193009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # least load. In case all devservers' load are higher than threshold, 1194009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # fall back to the old behavior by picking a devserver based on the 1195009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # payload URI, with which ImageServer.resolve will return a random 1196009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi # devserver based on the hash of the URI. 119701b28a630230336c3277dd7b9d375ee012931b77Dan Shi # The picked devserver needs to respect the location of the host if 1198a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock # 'prefer_local_devserver' is set to True or 'restricted_subnets' is 119901b28a630230336c3277dd7b9d375ee012931b77Dan Shi # set. 120001b28a630230336c3277dd7b9d375ee012931b77Dan Shi hostname = self._host.hostname if self._host else None 120101b28a630230336c3277dd7b9d375ee012931b77Dan Shi least_loaded_devserver = dev_server.get_least_loaded_devserver( 120201b28a630230336c3277dd7b9d375ee012931b77Dan Shi hostname=hostname) 12034e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi if least_loaded_devserver: 1204a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock logging.debug('Choosing the least loaded devserver: %s', 12054e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi least_loaded_devserver) 12064e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi autotest_devserver = dev_server.ImageServer(least_loaded_devserver) 12074e2153dd994a088d92e2a4c1cbee9043e08f9fe7Dan Shi else: 1208009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi logging.warning('No devserver meets the maximum load requirement. ' 1209a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 'Picking a random devserver to use.') 1210009ab000fbeeec0e0be9a2d6e744107a2b82306bDan Shi autotest_devserver = dev_server.ImageServer.resolve( 121169b9b975fccab1ede1e8849ed17e7e655a9d6b48Dan Shi test_conf['target_payload_uri'], host.hostname) 1212ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa devserver_hostname = urlparse.urlparse( 1213ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa autotest_devserver.url()).hostname 1214ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1215a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock logging.info('Devserver chosen for this run: %s', devserver_hostname) 1216a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock 1217f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Obtain a test platform implementation. 1218f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold test_platform = TestPlatform.create(host) 1219a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock test_platform.initialize(autotest_devserver, self.job.resultdir) 1220f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold 1221a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock # Stage source images and update payloads onto the devserver. 1222f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold staged_urls = test_platform.prep_artifacts(test_conf) 1223a0ca5707ed10a6575ed290f341294331455f7769Gilad Arnold self._source_image_installed = bool(staged_urls.source_url) 1224ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa 1225f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold # Prepare the DUT (install source version etc). 1226a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock test_platform.prep_device_for_update(test_conf['source_payload_uri']) 1227c6ed2f633a1c4609a4b212da66b3e506008ee3a7Nam T. Nguyen 1228a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock # Start the update. 1229ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa try: 1230f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self.run_update_test(test_platform, test_conf) 1231ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa except ExpectedUpdateEventChainFailed: 1232f1d1104c736f79145209c76a147c1334f8dbb6a9Gilad Arnold self._dump_update_engine_log(test_platform) 1233ed8c1858bc32b066e4fbe4100a9ad49bdf1adc61Chris Sosa raise 1234f789cf3a52c720344062f0a6c782bb758f08b189Don Garrett 1235a0dee8465654b79d97cbc1cfca82c42fc95bd8b5David Haddock test_platform.check_device_after_update() 1236