Skip to content

Commit

Permalink
[XB1] Refactor test retry loop to rerun net_args (#1647)
Browse files Browse the repository at this point in the history
b/299672207

Change-Id: Ic90a8805fa9bc6ec7a99ffe55c318f44b82f85cb
  • Loading branch information
TyHolc committed Sep 27, 2023
1 parent 0010204 commit 03aa6b7
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 30 deletions.
41 changes: 34 additions & 7 deletions starboard/xb1/tools/xb1_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@
_XB1_NET_LOG_PORT = 49353
_XB1_NET_ARG_PORT = 49355

# Number of times a test will try or retry.
_TEST_MAX_TRIES = 4
# Seconds to wait between retries (scales with backoff factor).
_TEST_RETRY_WAIT = 8
# Amount to multiply retry time with each failed attempt (i.e. 2 doubles the
# amount of time to wait between retries).
_TEST_RETRY_BACKOFF_FACTOR = 2

_PROCESS_TIMEOUT = 60 * 5.0
_PROCESS_KILL_TIMEOUT_SECONDS = 5.0

Expand Down Expand Up @@ -448,6 +456,31 @@ def CheckPackageIsDeployed(self):
return False
return package_list[package_index:].split('\n')[0].strip()

def RunTest(self, appx_name: str):
self.net_args_thread = None
attempt_num = 0
retry_wait_s = _TEST_RETRY_WAIT
while attempt_num < _TEST_MAX_TRIES:
if not self.net_args_thread or not self.net_args_thread.is_alive():
# This thread must start before the app executes or else it is possible
# the app will hang at _network_api.ExecuteBinary()
self.net_args_thread = net_args.NetArgsThread(self.device_id,
_XB1_NET_ARG_PORT,
self._target_args)
if self._network_api.ExecuteBinary(_DEFAULT_PACKAGE_NAME, appx_name):
break

if not self.net_args_thread.ArgsSent():
self._LogLn(
'Net Args were not sent to the test! This will likely cause '
'the test to fail!')
attempt_num += 1
self._LogLn(f'Retry attempt {attempt_num}.')
time.sleep(retry_wait_s)
retry_wait_s *= _TEST_RETRY_BACKOFF_FACTOR
if hasattr(self, 'net_args_thread'):
self.net_args_thread.join()

def Run(self):
# Only upload and install Appx on the first run.
if FirstRun():
Expand All @@ -474,20 +507,14 @@ def Run(self):

try:
self.Kill() # Kill existing running app.

# These threads must start before the app executes or else it is possible
# the app will hang at _network_api.ExecuteBinary()
self.net_args_thread = net_args.NetArgsThread(self.device_id,
_XB1_NET_ARG_PORT,
self._target_args)
# While binary is running, extract the net log and stream it to
# the output.
self.net_log_thread = net_log.NetLogThread(self.device_id,
_XB1_NET_LOG_PORT)

appx_name = ToAppxFriendlyName(self.target_name)

self._network_api.ExecuteBinary(_DEFAULT_PACKAGE_NAME, appx_name)
self.RunTest(appx_name)

while self._network_api.IsBinaryRunning(self.target_name):
self._Log(self.net_log_thread.GetLog())
Expand Down
39 changes: 16 additions & 23 deletions starboard/xb1/tools/xb1_network_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,8 @@ def FetchPackageFile(self,
return None
return None

def ExecuteBinary(self, partial_package_name, app_alias_name):
def ExecuteBinary(self, partial_package_name: str,
app_alias_name: str) -> bool:
default_relative_name = self._GetDefaultRelativeId(partial_package_name)
if not default_relative_name or not '!' in default_relative_name:
raise IOError('Could not resolve package name "' + partial_package_name +
Expand All @@ -432,33 +433,25 @@ def ExecuteBinary(self, partial_package_name, app_alias_name):
appid_64 = base64.b64encode(package_relative_id.encode('UTF-8'))
package_64 = base64.b64encode(default_relative_name.encode('UTF-8'))

retry_count = 4
# Time to wait between tries.
retry_wait_s = 8
try:
while retry_count > 0:
self.LogLn('Executing: ' + package_relative_id)
response = self._DoJsonRequest(
'POST',
_TASKMANAGER_ENDPOINT,
params={
'appid': appid_64,
'package': package_64
},
raise_on_failure=False)
if not response or response == requests.codes.OK:
self.LogLn('Execution successful')
break
self.LogLn('Execution not successful: ' + str(response))
self.LogLn('Retrying with ' + str(retry_count) + ' attempts remaining.')
time.sleep(retry_wait_s)
retry_count -= 1
# Double the wait time until the next attempt.
retry_wait_s *= 2
self.LogLn('Executing: ' + package_relative_id)
response = self._DoJsonRequest(
'POST',
_TASKMANAGER_ENDPOINT,
params={
'appid': appid_64,
'package': package_64
},
raise_on_failure=False)
if not response or response == requests.codes.OK:
self.LogLn('Execution successful')
return True
self.LogLn('Execution not successful: ' + str(response))
except Exception as err:
err_msg = '\n Failed to run:\n ' + package_relative_id + \
'\n because of:\n' + str(err)
raise IOError(err_msg) from err
return False

# Given a package name, return all files + directories.
# Throws IOError if the app is locked.
Expand Down

0 comments on commit 03aa6b7

Please sign in to comment.