1# Copyright 2017 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5# Update event types. 6EVENT_TYPE_DOWNLOAD_COMPLETE = '1' 7EVENT_TYPE_INSTALL_COMPLETE = '2' 8EVENT_TYPE_UPDATE_COMPLETE = '3' 9EVENT_TYPE_DOWNLOAD_STARTED = '13' 10EVENT_TYPE_DOWNLOAD_FINISHED = '14' 11EVENT_TYPE_REBOOTED_AFTER_UPDATE = '54' 12 13# Update event results. 14EVENT_RESULT_ERROR = '0' 15EVENT_RESULT_SUCCESS = '1' 16EVENT_RESULT_UPDATE_DEFERRED = '9' 17 18# Omaha event types/results, from update_engine/omaha_request_action.h 19# These are stored in dict form in order to easily print out the keys. 20EVENT_TYPE_DICT = { 21 EVENT_TYPE_DOWNLOAD_COMPLETE: 'download_complete', 22 EVENT_TYPE_INSTALL_COMPLETE: 'install_complete', 23 EVENT_TYPE_UPDATE_COMPLETE: 'update_complete', 24 EVENT_TYPE_DOWNLOAD_STARTED: 'download_started', 25 EVENT_TYPE_DOWNLOAD_FINISHED: 'download_finished', 26 EVENT_TYPE_REBOOTED_AFTER_UPDATE: 'rebooted_after_update' 27} 28 29EVENT_RESULT_DICT = { 30 EVENT_RESULT_ERROR: 'error', 31 EVENT_RESULT_SUCCESS: 'success', 32 EVENT_RESULT_UPDATE_DEFERRED: 'update_deferred' 33} 34 35 36def get_event_type(event_type_code): 37 """Utility to look up the different event type codes.""" 38 return EVENT_TYPE_DICT[event_type_code] 39 40 41def get_event_result(event_result_code): 42 """Utility to look up the different event result codes.""" 43 return EVENT_RESULT_DICT[event_result_code] 44 45 46class UpdateEngineEvent(object): 47 """This class represents a single EXPECTED update engine event. 48 49 This class's data will be compared against an ACTUAL event returned by 50 update_engine. 51 """ 52 53 def __init__(self, event_type=None, event_result=None, version=None, 54 previous_version=None, on_error=None): 55 """Initializes an event. 56 57 @param event_type: Expected event type. 58 @param event_result: Expected event result code. 59 @param version: Expected reported image version. 60 @param previous_version: Expected reported previous image version. 61 @param on_error: a function to call when the event's data is invalid. 62 """ 63 self._expected_attrs = { 64 'event_type': event_type, 65 'event_result': event_result, 66 'version': version, 67 'previous_version': previous_version, 68 } 69 self._on_error = on_error 70 71 72 def _verify_event_attribute(self, attr_name, expected_attr_val, 73 actual_attr_val): 74 """Compares a single attribute to ensure expected matches actual. 75 76 @param attr_name: name of the attribute to verify. 77 @param expected_attr_val: expected attribute value. 78 @param actual_attr_val: actual attribute value. 79 80 @return True if actual value is present and matches, False otherwise. 81 """ 82 # None values are assumed to be missing and non-matching. 83 if actual_attr_val is None: 84 return False 85 86 # We allow expected version numbers (e.g. 2940.0.0) to be contained in 87 # actual values (2940.0.0-a1) for developer images. 88 if (actual_attr_val == expected_attr_val or 89 ('version' in attr_name and expected_attr_val in actual_attr_val)): 90 return True 91 92 return False 93 94 95 def __str__(self): 96 """Returns a comma separated list of the event data.""" 97 return '{%s}' % ', '.join(['%s:%s' % (k, v) for k, v in 98 self._expected_attrs.iteritems()]) 99 100 def equals(self, actual_event): 101 """Compares this expected event with an actual event from the update. 102 103 @param actual_event: a dictionary containing event attributes. 104 105 @return An error message, or None if all attributes as expected. 106 """ 107 mismatched_attrs = [ 108 attr_name for attr_name, expected_attr_val 109 in self._expected_attrs.iteritems() 110 if (expected_attr_val and 111 not self._verify_event_attribute(attr_name, expected_attr_val, 112 actual_event.get(attr_name)))] 113 114 if not mismatched_attrs: 115 return None 116 117 return self._on_error(self._expected_attrs, actual_event, 118 mismatched_attrs)